blob: 9fa4db1af413f4525575d59cd847a5d47b977716 [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 Tanous3ccb3ad2023-01-13 17:40:03 -080031#include "utils/dbus_utils.hpp"
32#include "utils/time_utils.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070033
Myung Bae75e8e212023-11-30 12:53:46 -080034#include <systemd/sd-id128.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070035#include <systemd/sd-journal.h>
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060036#include <tinyxml2.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060037#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070038
Ed Tanous07c8c202022-07-11 10:08:08 -070039#include <boost/beast/http/verb.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070040#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080041#include <boost/system/linux_error.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070042#include <boost/url/format.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020043#include <sdbusplus/asio/property.hpp>
44#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045
George Liu7a1dbc42022-12-07 16:03:22 +080046#include <array>
George Liu647b3cd2021-07-05 12:43:56 +080047#include <charconv>
Abhilash Rajub5f288d2023-11-08 22:32:44 -060048#include <cstddef>
James Feist4418c7f2019-04-15 11:09:15 -070049#include <filesystem>
Ed Tanous18f8f602023-07-18 10:07:23 -070050#include <iterator>
Xiaochao Ma75710de2021-01-21 17:56:02 +080051#include <optional>
Ed Tanous3544d2a2023-08-06 18:12:20 -070052#include <ranges>
Ed Tanous26702d02021-11-03 15:02:33 -070053#include <span>
Ed Tanous18f8f602023-07-18 10:07:23 -070054#include <string>
Jason M. Billscd225da2019-05-08 15:31:57 -070055#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080056#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070057
58namespace redfish
59{
60
Patrick Williams89492a12023-05-10 07:51:34 -050061constexpr const char* crashdumpObject = "com.intel.crashdump";
62constexpr const char* crashdumpPath = "/com/intel/crashdump";
63constexpr const char* crashdumpInterface = "com.intel.crashdump";
64constexpr const char* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070065 "xyz.openbmc_project.Collection.DeleteAll";
Patrick Williams89492a12023-05-10 07:51:34 -050066constexpr const char* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070067 "com.intel.crashdump.OnDemand";
Patrick Williams89492a12023-05-10 07:51:34 -050068constexpr const char* crashdumpTelemetryInterface =
Kenny L. Ku6eda7682020-06-19 09:48:36 -070069 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070070
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060071enum class DumpCreationProgress
72{
73 DUMP_CREATE_SUCCESS,
74 DUMP_CREATE_FAILED,
75 DUMP_CREATE_INPROGRESS
76};
77
James Feistf6150402019-01-08 10:36:20 -080078namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -070079
Gunnar Mills1214b7e2020-06-04 10:11:30 -050080inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -070081{
Ed Tanousd4d25792020-09-29 15:15:03 -070082 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
83 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
84 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
85 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -070086 {
87 return "Critical";
88 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070089 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
90 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
91 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -070092 {
93 return "OK";
94 }
Ed Tanous3174e4d2020-10-07 11:41:22 -070095 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -070096 {
97 return "Warning";
98 }
99 return "";
100}
101
Abhishek Patel9017faf2021-09-14 22:48:55 -0500102inline std::optional<bool> getProviderNotifyAction(const std::string& notify)
103{
104 std::optional<bool> notifyAction;
105 if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify")
106 {
107 notifyAction = true;
108 }
109 else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit")
110 {
111 notifyAction = false;
112 }
113
114 return notifyAction;
115}
116
Ed Tanous18f8f602023-07-18 10:07:23 -0700117inline std::string getDumpPath(std::string_view dumpType)
118{
119 std::string dbusDumpPath = "/xyz/openbmc_project/dump/";
120 std::ranges::transform(dumpType, std::back_inserter(dbusDumpPath),
121 bmcweb::asciiToLower);
122
123 return dbusDumpPath;
124}
125
Ed Tanousdf254f22024-04-01 13:25:46 -0700126inline int getJournalMetadata(sd_journal* journal, std::string_view field,
127 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700128{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500129 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700130 size_t length = 0;
131 int ret = 0;
132 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800133 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
134 const void** dataVoid = reinterpret_cast<const void**>(&data);
135
136 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700137 if (ret < 0)
138 {
139 return ret;
140 }
Ed Tanous39e77502019-03-04 17:35:53 -0800141 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700142 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000143 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700144 return ret;
145}
146
Ed Tanousdf254f22024-04-01 13:25:46 -0700147inline int getJournalMetadata(sd_journal* journal, std::string_view field,
148 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700149{
150 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800151 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700152 // Get the metadata from the requested field of the journal entry
153 ret = getJournalMetadata(journal, field, metadata);
154 if (ret < 0)
155 {
156 return ret;
157 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000158 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700159 return ret;
160}
161
Ed Tanousdf254f22024-04-01 13:25:46 -0700162inline bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800163{
164 int ret = 0;
165 uint64_t timestamp = 0;
166 ret = sd_journal_get_realtime_usec(journal, &timestamp);
167 if (ret < 0)
168 {
Ed Tanous62598e32023-07-17 17:06:25 -0700169 BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret));
ZhikuiRena3316fc2020-01-29 14:58:08 -0800170 return false;
171 }
Konstantin Aladysheve645c5e2023-02-17 13:09:53 +0300172 entryTimestamp = redfish::time_utils::getDateTimeUintUs(timestamp);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500173 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800174}
Ed Tanous50b8a432022-02-03 16:29:50 -0800175
Ed Tanousdf254f22024-04-01 13:25:46 -0700176inline bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
177 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700178{
179 int ret = 0;
Myung Bae75e8e212023-11-30 12:53:46 -0800180 static sd_id128_t prevBootID{};
Jason M. Bills16428a12018-11-02 12:42:29 -0700181 static uint64_t prevTs = 0;
182 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700183 if (firstEntry)
184 {
Myung Bae75e8e212023-11-30 12:53:46 -0800185 prevBootID = {};
Jason M. Billse85d6b12019-07-29 17:01:15 -0700186 prevTs = 0;
187 }
188
Jason M. Bills16428a12018-11-02 12:42:29 -0700189 // Get the entry timestamp
190 uint64_t curTs = 0;
Myung Bae75e8e212023-11-30 12:53:46 -0800191 sd_id128_t curBootID{};
192 ret = sd_journal_get_monotonic_usec(journal, &curTs, &curBootID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700193 if (ret < 0)
194 {
Ed Tanous62598e32023-07-17 17:06:25 -0700195 BMCWEB_LOG_ERROR("Failed to read entry timestamp: {}", strerror(-ret));
Jason M. Bills16428a12018-11-02 12:42:29 -0700196 return false;
197 }
Myung Bae75e8e212023-11-30 12:53:46 -0800198 // If the timestamp isn't unique on the same boot, increment the index
199 bool sameBootIDs = sd_id128_equal(curBootID, prevBootID) != 0;
200 if (sameBootIDs && (curTs == prevTs))
Jason M. Bills16428a12018-11-02 12:42:29 -0700201 {
202 index++;
203 }
204 else
205 {
206 // Otherwise, reset it
207 index = 0;
208 }
Myung Bae75e8e212023-11-30 12:53:46 -0800209
210 if (!sameBootIDs)
211 {
212 // Save the bootID
213 prevBootID = curBootID;
214 }
Jason M. Bills16428a12018-11-02 12:42:29 -0700215 // Save the timestamp
216 prevTs = curTs;
217
Myung Bae75e8e212023-11-30 12:53:46 -0800218 // make entryID as <bootID>_<timestamp>[_<index>]
219 std::array<char, SD_ID128_STRING_MAX> bootIDStr{};
220 sd_id128_to_string(curBootID, bootIDStr.data());
221 entryID = std::format("{}_{}", bootIDStr.data(), curTs);
Jason M. Bills16428a12018-11-02 12:42:29 -0700222 if (index > 0)
223 {
224 entryID += "_" + std::to_string(index);
225 }
226 return true;
227}
228
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700230 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700231{
Ed Tanous271584a2019-07-09 16:24:22 -0700232 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700233 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700234 if (firstEntry)
235 {
236 prevTs = 0;
237 }
238
Jason M. Bills95820182019-04-22 16:25:34 -0700239 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700240 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700241 std::tm timeStruct = {};
242 std::istringstream entryStream(logEntry);
243 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
244 {
245 curTs = std::mktime(&timeStruct);
246 }
247 // If the timestamp isn't unique, increment the index
248 if (curTs == prevTs)
249 {
250 index++;
251 }
252 else
253 {
254 // Otherwise, reset it
255 index = 0;
256 }
257 // Save the timestamp
258 prevTs = curTs;
259
260 entryID = std::to_string(curTs);
261 if (index > 0)
262 {
263 entryID += "_" + std::to_string(index);
264 }
265 return true;
266}
267
Myung Bae75e8e212023-11-30 12:53:46 -0800268// Entry is formed like "BootID_timestamp" or "BootID_timestamp_index"
Ed Tanousdf254f22024-04-01 13:25:46 -0700269inline bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800270 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous099984c2024-04-01 13:23:11 -0700271 std::string_view entryIDStrView, sd_id128_t& bootID,
Myung Bae75e8e212023-11-30 12:53:46 -0800272 uint64_t& timestamp, uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700273{
Myung Bae75e8e212023-11-30 12:53:46 -0800274 // Convert the unique ID back to a bootID + timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -0800275 auto underscore1Pos = entryIDStrView.find('_');
276 if (underscore1Pos == std::string_view::npos)
277 {
278 // EntryID has no bootID or timestamp
Ed Tanous099984c2024-04-01 13:23:11 -0700279 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Myung Bae75e8e212023-11-30 12:53:46 -0800280 return false;
281 }
282
283 // EntryID has bootID + timestamp
284
285 // Convert entryIDViewString to BootID
286 // NOTE: bootID string which needs to be null-terminated for
287 // sd_id128_from_string()
Ed Tanous099984c2024-04-01 13:23:11 -0700288 std::string bootIDStr(entryIDStrView.substr(0, underscore1Pos));
Myung Bae75e8e212023-11-30 12:53:46 -0800289 if (sd_id128_from_string(bootIDStr.c_str(), &bootID) < 0)
290 {
Ed Tanous099984c2024-04-01 13:23:11 -0700291 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Myung Bae75e8e212023-11-30 12:53:46 -0800292 return false;
293 }
294
295 // Get the timestamp from entryID
Ed Tanous099984c2024-04-01 13:23:11 -0700296 entryIDStrView.remove_prefix(underscore1Pos + 1);
Myung Bae75e8e212023-11-30 12:53:46 -0800297
Ed Tanous099984c2024-04-01 13:23:11 -0700298 auto [timestampEnd, tstampEc] = std::from_chars(
299 entryIDStrView.begin(), entryIDStrView.end(), timestamp);
300 if (tstampEc != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700301 {
Ed Tanous099984c2024-04-01 13:23:11 -0700302 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
303 return false;
Jason M. Bills16428a12018-11-02 12:42:29 -0700304 }
Ed Tanous099984c2024-04-01 13:23:11 -0700305 entryIDStrView = std::string_view(
306 timestampEnd,
307 static_cast<size_t>(std::distance(timestampEnd, entryIDStrView.end())));
308 if (entryIDStrView.empty())
Jason M. Bills16428a12018-11-02 12:42:29 -0700309 {
Ed Tanous099984c2024-04-01 13:23:11 -0700310 index = 0U;
311 return true;
312 }
313 // Timestamp might include optional index, if two events happened at the
314 // same "time".
315 if (entryIDStrView[0] != '_')
316 {
317 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
318 return false;
319 }
320 entryIDStrView.remove_prefix(1);
321 auto [ptr, indexEc] = std::from_chars(entryIDStrView.begin(),
322 entryIDStrView.end(), index);
323 if (indexEc != std::errc() || ptr != entryIDStrView.end())
324 {
325 messages::resourceNotFound(asyncResp->res, "LogEntry", entryIDStrView);
Jason M. Bills16428a12018-11-02 12:42:29 -0700326 return false;
327 }
328 return true;
329}
330
Jason M. Bills95820182019-04-22 16:25:34 -0700331static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500332 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700333{
334 static const std::filesystem::path redfishLogDir = "/var/log";
335 static const std::string redfishLogFilename = "redfish";
336
337 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700339 std::filesystem::directory_iterator(redfishLogDir))
340 {
341 // If we find a redfish log file, save the path
342 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700343 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700344 {
345 redfishLogFiles.emplace_back(redfishLogDir / filename);
346 }
347 }
348 // As the log files rotate, they are appended with a ".#" that is higher for
349 // the older logs. Since we don't expect more than 10 log files, we
350 // can just sort the list to get them in order from newest to oldest
Ed Tanous3544d2a2023-08-06 18:12:20 -0700351 std::ranges::sort(redfishLogFiles);
Jason M. Bills95820182019-04-22 16:25:34 -0700352
353 return !redfishLogFiles.empty();
354}
355
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600356inline log_entry::OriginatorTypes
357 mapDbusOriginatorTypeToRedfish(const std::string& originatorType)
358{
359 if (originatorType ==
360 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client")
361 {
362 return log_entry::OriginatorTypes::Client;
363 }
364 if (originatorType ==
365 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Internal")
366 {
367 return log_entry::OriginatorTypes::Internal;
368 }
369 if (originatorType ==
370 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.SupportingService")
371 {
372 return log_entry::OriginatorTypes::SupportingService;
373 }
374 return log_entry::OriginatorTypes::Invalid;
375}
376
Claire Weinanaefe3782022-07-15 19:17:19 -0700377inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800378 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700379 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600380 std::string& originatorId, log_entry::OriginatorTypes& originatorType,
Claire Weinanaefe3782022-07-15 19:17:19 -0700381 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
382{
383 for (const auto& interfaceMap : object.second)
384 {
385 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
386 {
387 for (const auto& propertyMap : interfaceMap.second)
388 {
389 if (propertyMap.first == "Status")
390 {
391 const auto* status =
392 std::get_if<std::string>(&propertyMap.second);
393 if (status == nullptr)
394 {
395 messages::internalError(asyncResp->res);
396 break;
397 }
398 dumpStatus = *status;
399 }
400 }
401 }
402 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
403 {
404 for (const auto& propertyMap : interfaceMap.second)
405 {
406 if (propertyMap.first == "Size")
407 {
408 const auto* sizePtr =
409 std::get_if<uint64_t>(&propertyMap.second);
410 if (sizePtr == nullptr)
411 {
412 messages::internalError(asyncResp->res);
413 break;
414 }
415 size = *sizePtr;
416 break;
417 }
418 }
419 }
420 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
421 {
422 for (const auto& propertyMap : interfaceMap.second)
423 {
424 if (propertyMap.first == "Elapsed")
425 {
426 const uint64_t* usecsTimeStamp =
427 std::get_if<uint64_t>(&propertyMap.second);
428 if (usecsTimeStamp == nullptr)
429 {
430 messages::internalError(asyncResp->res);
431 break;
432 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700433 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700434 break;
435 }
436 }
437 }
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600438 else if (interfaceMap.first ==
439 "xyz.openbmc_project.Common.OriginatedBy")
440 {
441 for (const auto& propertyMap : interfaceMap.second)
442 {
443 if (propertyMap.first == "OriginatorId")
444 {
445 const std::string* id =
446 std::get_if<std::string>(&propertyMap.second);
447 if (id == nullptr)
448 {
449 messages::internalError(asyncResp->res);
450 break;
451 }
452 originatorId = *id;
453 }
454
455 if (propertyMap.first == "OriginatorType")
456 {
457 const std::string* type =
458 std::get_if<std::string>(&propertyMap.second);
459 if (type == nullptr)
460 {
461 messages::internalError(asyncResp->res);
462 break;
463 }
464
465 originatorType = mapDbusOriginatorTypeToRedfish(*type);
466 if (originatorType == log_entry::OriginatorTypes::Invalid)
467 {
468 messages::internalError(asyncResp->res);
469 break;
470 }
471 }
472 }
473 }
Claire Weinanaefe3782022-07-15 19:17:19 -0700474 }
475}
476
Nan Zhou21ab4042022-06-26 23:07:40 +0000477static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800478{
479 std::string entriesPath;
480
481 if (dumpType == "BMC")
482 {
483 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
484 }
485 else if (dumpType == "FaultLog")
486 {
487 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
488 }
489 else if (dumpType == "System")
490 {
491 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
492 }
493 else
494 {
Ed Tanous62598e32023-07-17 17:06:25 -0700495 BMCWEB_LOG_ERROR("getDumpEntriesPath() invalid dump type: {}",
496 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -0800497 }
498
499 // Returns empty string on error
500 return entriesPath;
501}
502
zhanghch058d1b46d2021-04-01 11:18:24 +0800503inline void
504 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
505 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500506{
Claire Weinanfdd26902022-03-01 14:18:25 -0800507 std::string entriesPath = getDumpEntriesPath(dumpType);
508 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500509 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500510 messages::internalError(asyncResp->res);
511 return;
512 }
513
George Liu5eb468d2023-06-20 17:03:24 +0800514 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
515 dbus::utility::getManagedObjects(
516 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800517 [asyncResp, entriesPath,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800518 dumpType](const boost::system::error_code& ec,
George Liu5eb468d2023-06-20 17:03:24 +0800519 const dbus::utility::ManagedObjectType& objects) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 if (ec)
521 {
Ed Tanous62598e32023-07-17 17:06:25 -0700522 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700523 messages::internalError(asyncResp->res);
524 return;
525 }
526
Claire Weinanfdd26902022-03-01 14:18:25 -0800527 // Remove ending slash
528 std::string odataIdStr = entriesPath;
529 if (!odataIdStr.empty())
530 {
531 odataIdStr.pop_back();
532 }
533
534 asyncResp->res.jsonValue["@odata.type"] =
535 "#LogEntryCollection.LogEntryCollection";
536 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
537 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
Patrick Williams89492a12023-05-10 07:51:34 -0500538 asyncResp->res.jsonValue["Description"] = "Collection of " + dumpType +
539 " Dump Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -0800540
Ed Tanous3544d2a2023-08-06 18:12:20 -0700541 nlohmann::json::array_t entriesArray;
Ed Tanous18f8f602023-07-18 10:07:23 -0700542 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700543
George Liu5eb468d2023-06-20 17:03:24 +0800544 dbus::utility::ManagedObjectType resp(objects);
Ed Tanous3544d2a2023-08-06 18:12:20 -0700545 std::ranges::sort(resp, [](const auto& l, const auto& r) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700546 return AlphanumLess<std::string>()(l.first.filename(),
547 r.first.filename());
548 });
549
550 for (auto& object : resp)
551 {
552 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500553 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700554 continue;
555 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700556 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700557 uint64_t size = 0;
558 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600559 std::string originatorId;
560 log_entry::OriginatorTypes originatorType =
561 log_entry::OriginatorTypes::Internal;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700562 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700563
564 std::string entryID = object.first.filename();
565 if (entryID.empty())
566 {
567 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500568 }
569
Claire Weinanc6fecda2022-07-15 10:43:25 -0700570 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600571 originatorId, originatorType,
Claire Weinanaefe3782022-07-15 19:17:19 -0700572 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700573
574 if (dumpStatus !=
575 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
576 !dumpStatus.empty())
577 {
578 // Dump status is not Complete, no need to enumerate
579 continue;
580 }
581
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600582 thisEntry["@odata.type"] = "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800583 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700584 thisEntry["Id"] = entryID;
585 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700587 thisEntry["Created"] =
588 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700589
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600590 if (!originatorId.empty())
591 {
592 thisEntry["Originator"] = originatorId;
593 thisEntry["OriginatorType"] = originatorType;
594 }
595
Ed Tanous002d39b2022-05-31 08:59:27 -0700596 if (dumpType == "BMC")
597 {
598 thisEntry["DiagnosticDataType"] = "Manager";
Patrick Williams89492a12023-05-10 07:51:34 -0500599 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
600 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800601 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700602 }
603 else if (dumpType == "System")
604 {
605 thisEntry["DiagnosticDataType"] = "OEM";
606 thisEntry["OEMDiagnosticDataType"] = "System";
Patrick Williams89492a12023-05-10 07:51:34 -0500607 thisEntry["AdditionalDataURI"] = entriesPath + entryID +
608 "/attachment";
Claire Weinanfdd26902022-03-01 14:18:25 -0800609 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700610 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500611 entriesArray.emplace_back(std::move(thisEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -0700612 }
613 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -0700614 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
Patrick Williams5a39f772023-10-20 11:20:21 -0500615 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500616}
617
zhanghch058d1b46d2021-04-01 11:18:24 +0800618inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700619 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800620 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500621{
Claire Weinanfdd26902022-03-01 14:18:25 -0800622 std::string entriesPath = getDumpEntriesPath(dumpType);
623 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500624 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500625 messages::internalError(asyncResp->res);
626 return;
627 }
628
George Liu5eb468d2023-06-20 17:03:24 +0800629 sdbusplus::message::object_path path("/xyz/openbmc_project/dump");
630 dbus::utility::getManagedObjects(
631 "xyz.openbmc_project.Dump.Manager", path,
Claire Weinanfdd26902022-03-01 14:18:25 -0800632 [asyncResp, entryID, dumpType,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800633 entriesPath](const boost::system::error_code& ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700634 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700635 if (ec)
636 {
Ed Tanous62598e32023-07-17 17:06:25 -0700637 BMCWEB_LOG_ERROR("DumpEntry resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -0700638 messages::internalError(asyncResp->res);
639 return;
640 }
641
642 bool foundDumpEntry = false;
Ed Tanous18f8f602023-07-18 10:07:23 -0700643 std::string dumpEntryPath = getDumpPath(dumpType) + "/entry/";
Ed Tanous002d39b2022-05-31 08:59:27 -0700644
645 for (const auto& objectPath : resp)
646 {
647 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500648 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700649 continue;
650 }
651
652 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700653 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 uint64_t size = 0;
655 std::string dumpStatus;
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600656 std::string originatorId;
657 log_entry::OriginatorTypes originatorType =
658 log_entry::OriginatorTypes::Internal;
Ed Tanous002d39b2022-05-31 08:59:27 -0700659
Claire Weinanaefe3782022-07-15 19:17:19 -0700660 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600661 timestampUs, originatorId,
662 originatorType, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700663
664 if (dumpStatus !=
665 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
666 !dumpStatus.empty())
667 {
668 // Dump status is not Complete
669 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200670 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
671 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500672 return;
673 }
674
Ed Tanous002d39b2022-05-31 08:59:27 -0700675 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600676 "#LogEntry.v1_11_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800677 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700678 asyncResp->res.jsonValue["Id"] = entryID;
679 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700681 asyncResp->res.jsonValue["Created"] =
682 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500683
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -0600684 if (!originatorId.empty())
685 {
686 asyncResp->res.jsonValue["Originator"] = originatorId;
687 asyncResp->res.jsonValue["OriginatorType"] = originatorType;
688 }
689
Ed Tanous002d39b2022-05-31 08:59:27 -0700690 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500691 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
693 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800694 entriesPath + entryID + "/attachment";
695 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500696 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700697 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500698 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700699 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
700 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
701 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800702 entriesPath + entryID + "/attachment";
703 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500704 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700705 }
706 if (!foundDumpEntry)
707 {
Ed Tanous62598e32023-07-17 17:06:25 -0700708 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
Myung Baeb90d14f2023-05-31 14:40:39 -0500709 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
710 entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -0700711 return;
712 }
Patrick Williams5a39f772023-10-20 11:20:21 -0500713 });
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500714}
715
zhanghch058d1b46d2021-04-01 11:18:24 +0800716inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800717 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500718 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500719{
Patrick Williams5a39f772023-10-20 11:20:21 -0500720 auto respHandler = [asyncResp,
721 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -0700722 BMCWEB_LOG_DEBUG("Dump Entry doDelete callback: Done");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500723 if (ec)
724 {
George Liu3de8d8b2021-03-22 17:49:39 +0800725 if (ec.value() == EBADR)
726 {
727 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
728 return;
729 }
Ed Tanous62598e32023-07-17 17:06:25 -0700730 BMCWEB_LOG_ERROR(
731 "Dump (DBus) doDelete respHandler got error {} entryID={}", ec,
732 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500733 messages::internalError(asyncResp->res);
734 return;
735 }
736 };
Ed Tanous18f8f602023-07-18 10:07:23 -0700737
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500738 crow::connections::systemBus->async_method_call(
739 respHandler, "xyz.openbmc_project.Dump.Manager",
Ed Tanous18f8f602023-07-18 10:07:23 -0700740 std::format("{}/entry/{}", getDumpPath(dumpType), entryID),
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500741 "xyz.openbmc_project.Object.Delete", "Delete");
742}
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600743inline bool checkSizeLimit(int fd, crow::Response& res)
744{
745 long long int size = lseek(fd, 0, SEEK_END);
746 if (size <= 0)
747 {
748 BMCWEB_LOG_ERROR("Failed to get size of file, lseek() returned {}",
749 size);
750 messages::internalError(res);
751 return false;
752 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500753
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600754 // Arbitrary max size of 20MB to accommodate BMC dumps
755 constexpr long long int maxFileSize = 20LL * 1024LL * 1024LL;
756 if (size > maxFileSize)
757 {
758 BMCWEB_LOG_ERROR("File size {} exceeds maximum allowed size of {}",
759 size, maxFileSize);
760 messages::internalError(res);
761 return false;
762 }
763 off_t rc = lseek(fd, 0, SEEK_SET);
764 if (rc < 0)
765 {
766 BMCWEB_LOG_ERROR("Failed to reset file offset to 0");
767 messages::internalError(res);
768 return false;
769 }
770 return true;
771}
Carson Labrado168d1b12023-03-27 17:04:46 +0000772inline void
773 downloadEntryCallback(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
774 const std::string& entryID,
775 const std::string& downloadEntryType,
776 const boost::system::error_code& ec,
777 const sdbusplus::message::unix_fd& unixfd)
778{
779 if (ec.value() == EBADR)
780 {
781 messages::resourceNotFound(asyncResp->res, "EntryAttachment", entryID);
782 return;
783 }
784 if (ec)
785 {
786 BMCWEB_LOG_ERROR("DBUS response error: {}", ec);
787 messages::internalError(asyncResp->res);
788 return;
789 }
790
791 // Make sure we know how to process the retrieved entry attachment
792 if ((downloadEntryType != "BMC") && (downloadEntryType != "System"))
793 {
794 BMCWEB_LOG_ERROR("downloadEntryCallback() invalid entry type: {}",
795 downloadEntryType);
796 messages::internalError(asyncResp->res);
797 }
798
799 int fd = -1;
800 fd = dup(unixfd);
801 if (fd < 0)
802 {
803 BMCWEB_LOG_ERROR("Failed to open file");
804 messages::internalError(asyncResp->res);
805 return;
806 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600807 if (!checkSizeLimit(fd, asyncResp->res))
Carson Labrado168d1b12023-03-27 17:04:46 +0000808 {
Carson Labrado168d1b12023-03-27 17:04:46 +0000809 close(fd);
810 return;
811 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000812 if (downloadEntryType == "System")
813 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600814 if (!asyncResp->res.openFd(fd, bmcweb::EncodingType::Base64))
815 {
816 messages::internalError(asyncResp->res);
817 close(fd);
818 return;
819 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000820 asyncResp->res.addHeader(
821 boost::beast::http::field::content_transfer_encoding, "Base64");
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600822 return;
Carson Labrado168d1b12023-03-27 17:04:46 +0000823 }
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600824 if (!asyncResp->res.openFd(fd))
Ed Tanous27b0cf92023-08-07 12:02:40 -0700825 {
Abhilash Rajub5f288d2023-11-08 22:32:44 -0600826 messages::internalError(asyncResp->res);
827 close(fd);
828 return;
Ed Tanous27b0cf92023-08-07 12:02:40 -0700829 }
Carson Labrado168d1b12023-03-27 17:04:46 +0000830 asyncResp->res.addHeader(boost::beast::http::field::content_type,
831 "application/octet-stream");
832}
833
834inline void
835 downloadDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
836 const std::string& entryID, const std::string& dumpType)
837{
838 if (dumpType != "BMC")
839 {
840 BMCWEB_LOG_WARNING("Can't find Dump Entry {}", entryID);
841 messages::resourceNotFound(asyncResp->res, dumpType + " dump", entryID);
842 return;
843 }
844
Ed Tanous18f8f602023-07-18 10:07:23 -0700845 std::string dumpEntryPath = std::format("{}/entry/{}",
846 getDumpPath(dumpType), entryID);
Carson Labrado168d1b12023-03-27 17:04:46 +0000847
848 auto downloadDumpEntryHandler =
849 [asyncResp, entryID,
850 dumpType](const boost::system::error_code& ec,
851 const sdbusplus::message::unix_fd& unixfd) {
852 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
853 };
854
855 crow::connections::systemBus->async_method_call(
856 std::move(downloadDumpEntryHandler), "xyz.openbmc_project.Dump.Manager",
857 dumpEntryPath, "xyz.openbmc_project.Dump.Entry", "GetFileHandle");
858}
859
860inline void
861 downloadEventLogEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
862 const std::string& systemName,
863 const std::string& entryID,
864 const std::string& dumpType)
865{
866 if constexpr (bmcwebEnableMultiHost)
867 {
868 // Option currently returns no systems. TBD
869 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
870 systemName);
871 return;
872 }
873 if (systemName != "system")
874 {
875 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
876 systemName);
877 return;
878 }
879
880 std::string entryPath =
881 sdbusplus::message::object_path("/xyz/openbmc_project/logging/entry") /
882 entryID;
883
884 auto downloadEventLogEntryHandler =
885 [asyncResp, entryID,
886 dumpType](const boost::system::error_code& ec,
887 const sdbusplus::message::unix_fd& unixfd) {
888 downloadEntryCallback(asyncResp, entryID, dumpType, ec, unixfd);
889 };
890
891 crow::connections::systemBus->async_method_call(
892 std::move(downloadEventLogEntryHandler), "xyz.openbmc_project.Logging",
893 entryPath, "xyz.openbmc_project.Logging.Entry", "GetEntry");
894}
895
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600896inline DumpCreationProgress
897 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500898{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600899 if (status ==
900 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
901 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
902 {
903 return DumpCreationProgress::DUMP_CREATE_FAILED;
904 }
905 if (status ==
906 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
907 {
908 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
909 }
910 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
911}
912
913inline DumpCreationProgress
914 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
915{
916 for (const auto& [key, val] : values)
917 {
918 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700919 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600920 const std::string* value = std::get_if<std::string>(&val);
921 if (value == nullptr)
922 {
Ed Tanous62598e32023-07-17 17:06:25 -0700923 BMCWEB_LOG_ERROR("Status property value is null");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600924 return DumpCreationProgress::DUMP_CREATE_FAILED;
925 }
926 return mapDbusStatusToDumpProgress(*value);
927 }
928 }
929 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
930}
931
932inline std::string getDumpEntryPath(const std::string& dumpPath)
933{
934 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
935 {
936 return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
937 }
938 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
939 {
940 return "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
941 }
942 return "";
943}
944
945inline void createDumpTaskCallback(
946 task::Payload&& payload,
947 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
948 const sdbusplus::message::object_path& createdObjPath)
949{
950 const std::string dumpPath = createdObjPath.parent_path().str;
951 const std::string dumpId = createdObjPath.filename();
952
953 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
954
955 if (dumpEntryPath.empty())
956 {
Ed Tanous62598e32023-07-17 17:06:25 -0700957 BMCWEB_LOG_ERROR("Invalid dump type received");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600958 messages::internalError(asyncResp->res);
959 return;
960 }
961
962 crow::connections::systemBus->async_method_call(
Ed Tanous8cb2c022024-03-27 16:31:46 -0700963 [asyncResp, payload = std::move(payload), createdObjPath,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600964 dumpEntryPath{std::move(dumpEntryPath)},
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800965 dumpId](const boost::system::error_code& ec,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600966 const std::string& introspectXml) {
967 if (ec)
968 {
Ed Tanous62598e32023-07-17 17:06:25 -0700969 BMCWEB_LOG_ERROR("Introspect call failed with error: {}",
970 ec.message());
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600971 messages::internalError(asyncResp->res);
972 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700973 }
974
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600975 // Check if the created dump object has implemented Progress
976 // interface to track dump completion. If yes, fetch the "Status"
977 // property of the interface, modify the task state accordingly.
978 // Else, return task completed.
979 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700980
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600981 doc.Parse(introspectXml.data(), introspectXml.size());
982 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
983 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700984 {
Ed Tanous62598e32023-07-17 17:06:25 -0700985 BMCWEB_LOG_ERROR("XML document failed to parse");
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600986 messages::internalError(asyncResp->res);
987 return;
988 }
989 tinyxml2::XMLElement* interfaceNode =
990 pRoot->FirstChildElement("interface");
991
992 bool isProgressIntfPresent = false;
993 while (interfaceNode != nullptr)
994 {
995 const char* thisInterfaceName = interfaceNode->Attribute("name");
996 if (thisInterfaceName != nullptr)
997 {
998 if (thisInterfaceName ==
999 std::string_view("xyz.openbmc_project.Common.Progress"))
1000 {
1001 interfaceNode =
1002 interfaceNode->NextSiblingElement("interface");
1003 continue;
1004 }
1005 isProgressIntfPresent = true;
1006 break;
1007 }
1008 interfaceNode = interfaceNode->NextSiblingElement("interface");
1009 }
1010
1011 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
1012 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
Ed Tanous8b242752023-06-27 17:17:13 -07001013 const boost::system::error_code& ec2, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001014 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07001015 if (ec2)
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001016 {
Ed Tanous62598e32023-07-17 17:06:25 -07001017 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1018 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001019 taskData->messages.emplace_back(messages::internalError());
1020 taskData->state = "Cancelled";
1021 return task::completed;
1022 }
1023
1024 if (isProgressIntfPresent)
1025 {
1026 dbus::utility::DBusPropertiesMap values;
1027 std::string prop;
1028 msg.read(prop, values);
1029
1030 DumpCreationProgress dumpStatus =
1031 getDumpCompletionStatus(values);
1032 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
1033 {
Ed Tanous62598e32023-07-17 17:06:25 -07001034 BMCWEB_LOG_ERROR("{}: Error in creating dump",
1035 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001036 taskData->state = "Cancelled";
1037 return task::completed;
1038 }
1039
1040 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
1041 {
Ed Tanous62598e32023-07-17 17:06:25 -07001042 BMCWEB_LOG_DEBUG("{}: Dump creation task is in progress",
1043 createdObjPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001044 return !task::completed;
1045 }
1046 }
1047
Ed Tanous002d39b2022-05-31 08:59:27 -07001048 nlohmann::json retMessage = messages::success();
1049 taskData->messages.emplace_back(retMessage);
1050
Ed Tanousc51a58e2023-03-27 14:43:19 -07001051 boost::urls::url url = boost::urls::format(
1052 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/{}", dumpId);
1053
1054 std::string headerLoc = "Location: ";
1055 headerLoc += url.buffer();
1056
Ed Tanous002d39b2022-05-31 08:59:27 -07001057 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
1058
Ed Tanous62598e32023-07-17 17:06:25 -07001059 BMCWEB_LOG_DEBUG("{}: Dump creation task completed",
1060 createdObjPath.str);
Ed Tanous002d39b2022-05-31 08:59:27 -07001061 taskData->state = "Completed";
1062 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05001063 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001064 "type='signal',interface='org.freedesktop.DBus.Properties',"
1065 "member='PropertiesChanged',path='" +
1066 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001067
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001068 // The task timer is set to max time limit within which the
1069 // requested dump will be collected.
1070 task->startTimer(std::chrono::minutes(6));
1071 task->populateResp(asyncResp->res);
1072 task->payload.emplace(payload);
Patrick Williams5a39f772023-10-20 11:20:21 -05001073 },
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001074 "xyz.openbmc_project.Dump.Manager", createdObjPath,
1075 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001076}
1077
zhanghch058d1b46d2021-04-01 11:18:24 +08001078inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1079 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001080{
Claire Weinanfdd26902022-03-01 14:18:25 -08001081 std::string dumpPath = getDumpEntriesPath(dumpType);
1082 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001083 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001084 messages::internalError(asyncResp->res);
1085 return;
1086 }
1087
1088 std::optional<std::string> diagnosticDataType;
1089 std::optional<std::string> oemDiagnosticDataType;
1090
Willy Tu15ed6782021-12-14 11:03:16 -08001091 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001092 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
1093 "OEMDiagnosticDataType", oemDiagnosticDataType))
1094 {
1095 return;
1096 }
1097
1098 if (dumpType == "System")
1099 {
1100 if (!oemDiagnosticDataType || !diagnosticDataType)
1101 {
Ed Tanous62598e32023-07-17 17:06:25 -07001102 BMCWEB_LOG_ERROR(
1103 "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001104 messages::actionParameterMissing(
1105 asyncResp->res, "CollectDiagnosticData",
1106 "DiagnosticDataType & OEMDiagnosticDataType");
1107 return;
1108 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001109 if ((*oemDiagnosticDataType != "System") ||
1110 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001111 {
Ed Tanous62598e32023-07-17 17:06:25 -07001112 BMCWEB_LOG_ERROR("Wrong parameter values passed");
Ed Tanousace85d62021-10-26 12:45:59 -07001113 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001114 return;
1115 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001116 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001117 }
1118 else if (dumpType == "BMC")
1119 {
1120 if (!diagnosticDataType)
1121 {
Ed Tanous62598e32023-07-17 17:06:25 -07001122 BMCWEB_LOG_ERROR(
1123 "CreateDump action parameter 'DiagnosticDataType' not found!");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001124 messages::actionParameterMissing(
1125 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
1126 return;
1127 }
Ed Tanous3174e4d2020-10-07 11:41:22 -07001128 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001129 {
Ed Tanous62598e32023-07-17 17:06:25 -07001130 BMCWEB_LOG_ERROR(
1131 "Wrong parameter value passed for 'DiagnosticDataType'");
Ed Tanousace85d62021-10-26 12:45:59 -07001132 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001133 return;
1134 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001135 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
1136 }
1137 else
1138 {
Ed Tanous62598e32023-07-17 17:06:25 -07001139 BMCWEB_LOG_ERROR("CreateDump failed. Unknown dump type");
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001140 messages::internalError(asyncResp->res);
1141 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001142 }
1143
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001144 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
1145 createDumpParamVec;
1146
Carson Labradof574a8e2023-03-22 02:26:00 +00001147 if (req.session != nullptr)
1148 {
1149 createDumpParamVec.emplace_back(
1150 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorId",
1151 req.session->clientIp);
1152 createDumpParamVec.emplace_back(
1153 "xyz.openbmc_project.Dump.Create.CreateParameters.OriginatorType",
1154 "xyz.openbmc_project.Common.OriginatedBy.OriginatorTypes.Client");
1155 }
Asmitha Karunanithi68dd0752022-11-15 11:33:46 -06001156
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001157 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001158 [asyncResp, payload(task::Payload(req)),
1159 dumpPath](const boost::system::error_code& ec,
1160 const sdbusplus::message_t& msg,
1161 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -07001162 if (ec)
1163 {
Ed Tanous62598e32023-07-17 17:06:25 -07001164 BMCWEB_LOG_ERROR("CreateDump resp_handler got error {}", ec);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001165 const sd_bus_error* dbusError = msg.get_error();
1166 if (dbusError == nullptr)
1167 {
1168 messages::internalError(asyncResp->res);
1169 return;
1170 }
1171
Ed Tanous62598e32023-07-17 17:06:25 -07001172 BMCWEB_LOG_ERROR("CreateDump DBus error: {} and error msg: {}",
1173 dbusError->name, dbusError->message);
Asmitha Karunanithi59075712021-10-22 01:17:41 -05001174 if (std::string_view(
1175 "xyz.openbmc_project.Common.Error.NotAllowed") ==
1176 dbusError->name)
1177 {
1178 messages::resourceInStandby(asyncResp->res);
1179 return;
1180 }
1181 if (std::string_view(
1182 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
1183 dbusError->name)
1184 {
1185 messages::serviceDisabled(asyncResp->res, dumpPath);
1186 return;
1187 }
1188 if (std::string_view(
1189 "xyz.openbmc_project.Common.Error.Unavailable") ==
1190 dbusError->name)
1191 {
1192 messages::resourceInUse(asyncResp->res);
1193 return;
1194 }
1195 // Other Dbus errors such as:
1196 // xyz.openbmc_project.Common.Error.InvalidArgument &
1197 // org.freedesktop.DBus.Error.InvalidArgs are all related to
1198 // the dbus call that is made here in the bmcweb
1199 // implementation and has nothing to do with the client's
1200 // input in the request. Hence, returning internal error
1201 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -07001202 messages::internalError(asyncResp->res);
1203 return;
1204 }
Ed Tanous62598e32023-07-17 17:06:25 -07001205 BMCWEB_LOG_DEBUG("Dump Created. Path: {}", objPath.str);
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001206 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Patrick Williams5a39f772023-10-20 11:20:21 -05001207 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001208 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -06001209 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -05001210}
1211
zhanghch058d1b46d2021-04-01 11:18:24 +08001212inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1213 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001214{
Claire Weinan0d946212022-07-13 19:40:19 -07001215 crow::connections::systemBus->async_method_call(
1216 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001217 if (ec)
1218 {
Ed Tanous62598e32023-07-17 17:06:25 -07001219 BMCWEB_LOG_ERROR("clearDump resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001220 messages::internalError(asyncResp->res);
1221 return;
1222 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001223 },
Ed Tanous18f8f602023-07-18 10:07:23 -07001224 "xyz.openbmc_project.Dump.Manager", getDumpPath(dumpType),
Claire Weinan0d946212022-07-13 19:40:19 -07001225 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001226}
1227
Ed Tanousdf254f22024-04-01 13:25:46 -07001228inline void
Ed Tanousb9d36b42022-02-26 21:42:46 -08001229 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
1230 std::string& filename, std::string& timestamp,
1231 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001232{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001233 const std::string* filenamePtr = nullptr;
1234 const std::string* timestampPtr = nullptr;
1235 const std::string* logfilePtr = nullptr;
1236
1237 const bool success = sdbusplus::unpackPropertiesNoThrow(
1238 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1239 "Filename", filenamePtr, "Log", logfilePtr);
1240
1241 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001242 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001243 return;
1244 }
1245
1246 if (filenamePtr != nullptr)
1247 {
1248 filename = *filenamePtr;
1249 }
1250
1251 if (timestampPtr != nullptr)
1252 {
1253 timestamp = *timestampPtr;
1254 }
1255
1256 if (logfilePtr != nullptr)
1257 {
1258 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001259 }
1260}
1261
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001262inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001263{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001264 /**
1265 * Functions triggers appropriate requests on DBus
1266 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001267 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001268 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001269 .methods(boost::beast::http::verb::get)(
1270 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001271 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1272 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001273 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001274 {
1275 return;
1276 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001277 if constexpr (bmcwebEnableMultiHost)
1278 {
1279 // Option currently returns no systems. TBD
1280 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1281 systemName);
1282 return;
1283 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001284 if (systemName != "system")
1285 {
1286 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1287 systemName);
1288 return;
1289 }
1290
Ed Tanous002d39b2022-05-31 08:59:27 -07001291 // Collections don't include the static data added by SubRoute
1292 // because it has a duplicate entry for members
1293 asyncResp->res.jsonValue["@odata.type"] =
1294 "#LogServiceCollection.LogServiceCollection";
1295 asyncResp->res.jsonValue["@odata.id"] =
1296 "/redfish/v1/Systems/system/LogServices";
1297 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1298 asyncResp->res.jsonValue["Description"] =
1299 "Collection of LogServices for this Computer System";
1300 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1301 logServiceArray = nlohmann::json::array();
1302 nlohmann::json::object_t eventLog;
1303 eventLog["@odata.id"] =
1304 "/redfish/v1/Systems/system/LogServices/EventLog";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001305 logServiceArray.emplace_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001306#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001307 nlohmann::json::object_t dumpLog;
1308 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001309 logServiceArray.emplace_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -06001310#endif
1311
Jason M. Billsd53dd412019-02-12 17:16:22 -08001312#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001313 nlohmann::json::object_t crashdump;
1314 crashdump["@odata.id"] =
1315 "/redfish/v1/Systems/system/LogServices/Crashdump";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001316 logServiceArray.emplace_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -08001317#endif
Spencer Kub7028eb2021-10-26 15:27:35 +08001318
1319#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -07001320 nlohmann::json::object_t hostlogger;
1321 hostlogger["@odata.id"] =
1322 "/redfish/v1/Systems/system/LogServices/HostLogger";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001323 logServiceArray.emplace_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +08001324#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07001325 asyncResp->res.jsonValue["Members@odata.count"] =
1326 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001327
George Liu7a1dbc42022-12-07 16:03:22 +08001328 constexpr std::array<std::string_view, 1> interfaces = {
1329 "xyz.openbmc_project.State.Boot.PostCode"};
1330 dbus::utility::getSubTreePaths(
1331 "/", 0, interfaces,
1332 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001333 const dbus::utility::MapperGetSubTreePathsResponse&
1334 subtreePath) {
1335 if (ec)
1336 {
Ed Tanous62598e32023-07-17 17:06:25 -07001337 BMCWEB_LOG_ERROR("{}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001338 return;
1339 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001340
Ed Tanous002d39b2022-05-31 08:59:27 -07001341 for (const auto& pathStr : subtreePath)
1342 {
1343 if (pathStr.find("PostCode") != std::string::npos)
1344 {
1345 nlohmann::json& logServiceArrayLocal =
1346 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001347 nlohmann::json::object_t member;
1348 member["@odata.id"] =
1349 "/redfish/v1/Systems/system/LogServices/PostCodes";
1350
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001351 logServiceArrayLocal.emplace_back(std::move(member));
Ed Tanous613dabe2022-07-09 11:17:36 -07001352
Ed Tanous002d39b2022-05-31 08:59:27 -07001353 asyncResp->res.jsonValue["Members@odata.count"] =
1354 logServiceArrayLocal.size();
1355 return;
1356 }
1357 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001358 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001359 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001360}
1361
1362inline void requestRoutesEventLogService(App& app)
1363{
Ed Tanous22d268c2022-05-19 09:39:07 -07001364 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001365 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001366 .methods(boost::beast::http::verb::get)(
1367 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001368 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1369 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001370 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001371 {
1372 return;
1373 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001374 if (systemName != "system")
1375 {
1376 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1377 systemName);
1378 return;
1379 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001380 asyncResp->res.jsonValue["@odata.id"] =
1381 "/redfish/v1/Systems/system/LogServices/EventLog";
1382 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05001383 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07001384 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1385 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1386 asyncResp->res.jsonValue["Id"] = "EventLog";
1387 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301388
Ed Tanous002d39b2022-05-31 08:59:27 -07001389 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001390 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301391
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1393 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1394 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301395
Ed Tanous002d39b2022-05-31 08:59:27 -07001396 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1397 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1398 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001399
Ed Tanous002d39b2022-05-31 08:59:27 -07001400 {"target",
1401 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
Patrick Williams5a39f772023-10-20 11:20:21 -05001402 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001403}
1404
1405inline void requestRoutesJournalEventLogClear(App& app)
1406{
Jason M. Bills4978b632022-02-22 14:17:43 -08001407 BMCWEB_ROUTE(
1408 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001409 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001410 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001411 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001412 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001413 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1414 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001415 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001416 {
1417 return;
1418 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001419 if (systemName != "system")
1420 {
1421 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1422 systemName);
1423 return;
1424 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001425 // Clear the EventLog by deleting the log files
1426 std::vector<std::filesystem::path> redfishLogFiles;
1427 if (getRedfishLogFiles(redfishLogFiles))
1428 {
1429 for (const std::filesystem::path& file : redfishLogFiles)
1430 {
1431 std::error_code ec;
1432 std::filesystem::remove(file, ec);
1433 }
1434 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001435
Ed Tanous002d39b2022-05-31 08:59:27 -07001436 // Reload rsyslog so it knows to start new log files
1437 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001438 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001439 if (ec)
1440 {
Ed Tanous62598e32023-07-17 17:06:25 -07001441 BMCWEB_LOG_ERROR("Failed to reload rsyslog: {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001442 messages::internalError(asyncResp->res);
1443 return;
1444 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001445
Ed Tanous002d39b2022-05-31 08:59:27 -07001446 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05001447 },
Ed Tanous002d39b2022-05-31 08:59:27 -07001448 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1449 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1450 "replace");
Patrick Williams5a39f772023-10-20 11:20:21 -05001451 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001452}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001453
Jason M. Billsac992cd2022-06-24 13:31:46 -07001454enum class LogParseError
1455{
1456 success,
1457 parseFailed,
1458 messageIdNotInRegistry,
1459};
1460
1461static LogParseError
1462 fillEventLogEntryJson(const std::string& logEntryID,
1463 const std::string& logEntry,
1464 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001465{
Jason M. Bills95820182019-04-22 16:25:34 -07001466 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001467 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001468 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001469 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001470 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001471 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001472 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001473 std::string timestamp = logEntry.substr(0, space);
1474 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001475 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001476 if (entryStart == std::string::npos)
1477 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001478 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001479 }
1480 std::string_view entry(logEntry);
1481 entry.remove_prefix(entryStart);
1482 // Use split to separate the entry into its fields
1483 std::vector<std::string> logEntryFields;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08001484 bmcweb::split(logEntryFields, entry, ',');
Jason M. Billscd225da2019-05-08 15:31:57 -07001485 // We need at least a MessageId to be valid
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001486 auto logEntryIter = logEntryFields.begin();
1487 if (logEntryIter == logEntryFields.end())
Jason M. Billscd225da2019-05-08 15:31:57 -07001488 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001489 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001490 }
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001491 std::string& messageID = *logEntryIter;
Jason M. Bills4851d452019-03-28 11:27:48 -07001492 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001493 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001494
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001495 logEntryIter++;
Sui Chen54417b02022-03-24 14:59:52 -07001496 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001497 {
Ed Tanous62598e32023-07-17 17:06:25 -07001498 BMCWEB_LOG_WARNING("Log entry not found in registry: {}", logEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001499 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001500 }
1501
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001502 std::vector<std::string_view> messageArgs(logEntryIter,
1503 logEntryFields.end());
Ed Tanousc05bba42023-06-28 08:33:29 -07001504 messageArgs.resize(message->numberOfArgs);
1505
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001506 std::string msg = redfish::registries::fillMessageArgs(messageArgs,
1507 message->message);
1508 if (msg.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001509 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08001510 return LogParseError::parseFailed;
Jason M. Bills4851d452019-03-28 11:27:48 -07001511 }
1512
Jason M. Bills95820182019-04-22 16:25:34 -07001513 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1514 // format which matches the Redfish format except for the fractional seconds
1515 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001516 std::size_t dot = timestamp.find_first_of('.');
1517 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001518 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001519 {
Jason M. Bills95820182019-04-22 16:25:34 -07001520 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001521 }
1522
1523 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001524 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001525 logEntryJson["@odata.id"] = boost::urls::format(
1526 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
1527 logEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07001528 logEntryJson["Name"] = "System Event Log Entry";
1529 logEntryJson["Id"] = logEntryID;
1530 logEntryJson["Message"] = std::move(msg);
1531 logEntryJson["MessageId"] = std::move(messageID);
1532 logEntryJson["MessageArgs"] = messageArgs;
1533 logEntryJson["EntryType"] = "Event";
1534 logEntryJson["Severity"] = message->messageSeverity;
1535 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001536 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001537}
1538
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001539inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001540{
Ed Tanous22d268c2022-05-19 09:39:07 -07001541 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001542 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001543 .methods(boost::beast::http::verb::get)(
1544 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001545 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1546 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001547 query_param::QueryCapabilities capabilities = {
1548 .canDelegateTop = true,
1549 .canDelegateSkip = true,
1550 };
1551 query_param::Query delegatedQuery;
1552 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001553 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001554 {
1555 return;
1556 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001557 if constexpr (bmcwebEnableMultiHost)
1558 {
1559 // Option currently returns no systems. TBD
1560 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1561 systemName);
1562 return;
1563 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001564 if (systemName != "system")
1565 {
1566 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1567 systemName);
1568 return;
1569 }
1570
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001571 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001572 size_t skip = delegatedQuery.skip.value_or(0);
1573
Ed Tanous002d39b2022-05-31 08:59:27 -07001574 // Collections don't include the static data added by SubRoute
1575 // because it has a duplicate entry for members
1576 asyncResp->res.jsonValue["@odata.type"] =
1577 "#LogEntryCollection.LogEntryCollection";
1578 asyncResp->res.jsonValue["@odata.id"] =
1579 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1580 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1581 asyncResp->res.jsonValue["Description"] =
1582 "Collection of System Event Log Entries";
1583
1584 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1585 logEntryArray = nlohmann::json::array();
1586 // Go through the log files and create a unique ID for each
1587 // entry
1588 std::vector<std::filesystem::path> redfishLogFiles;
1589 getRedfishLogFiles(redfishLogFiles);
1590 uint64_t entryCount = 0;
1591 std::string logEntry;
1592
1593 // Oldest logs are in the last file, so start there and loop
1594 // backwards
1595 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1596 it++)
1597 {
1598 std::ifstream logStream(*it);
1599 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001600 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001601 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001602 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001603
Ed Tanous002d39b2022-05-31 08:59:27 -07001604 // Reset the unique ID on the first entry
1605 bool firstEntry = true;
1606 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001607 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001608 std::string idStr;
1609 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001610 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001611 continue;
1612 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001613 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001614
Jason M. Billsde703c52022-06-23 14:19:04 -07001615 nlohmann::json::object_t bmcLogEntry;
Patrick Williams89492a12023-05-10 07:51:34 -05001616 LogParseError status = fillEventLogEntryJson(idStr, logEntry,
1617 bmcLogEntry);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001618 if (status == LogParseError::messageIdNotInRegistry)
1619 {
1620 continue;
1621 }
1622 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 {
1624 messages::internalError(asyncResp->res);
1625 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001626 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001627
Jason M. Billsde703c52022-06-23 14:19:04 -07001628 entryCount++;
1629 // Handle paging using skip (number of entries to skip from the
1630 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001631 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001632 {
1633 continue;
1634 }
1635
Patrick Williamsb2ba3072023-05-12 10:27:39 -05001636 logEntryArray.emplace_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001637 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001638 }
1639 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001640 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001641 {
1642 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1643 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001644 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001645 }
Patrick Williams5a39f772023-10-20 11:20:21 -05001646 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001647}
Chicago Duan336e96c2019-07-15 14:22:08 +08001648
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001649inline void requestRoutesJournalEventLogEntry(App& app)
1650{
1651 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001652 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001653 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001654 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001655 [&app](const crow::Request& req,
1656 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001657 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001658 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001659 {
1660 return;
1661 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001662 if constexpr (bmcwebEnableMultiHost)
1663 {
1664 // Option currently returns no systems. TBD
1665 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1666 systemName);
1667 return;
1668 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001669
1670 if (systemName != "system")
1671 {
1672 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1673 systemName);
1674 return;
1675 }
1676
Ed Tanous002d39b2022-05-31 08:59:27 -07001677 const std::string& targetID = param;
1678
1679 // Go through the log files and check the unique ID for each
1680 // entry to find the target entry
1681 std::vector<std::filesystem::path> redfishLogFiles;
1682 getRedfishLogFiles(redfishLogFiles);
1683 std::string logEntry;
1684
1685 // Oldest logs are in the last file, so start there and loop
1686 // backwards
1687 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1688 it++)
1689 {
1690 std::ifstream logStream(*it);
1691 if (!logStream.is_open())
1692 {
1693 continue;
1694 }
1695
1696 // Reset the unique ID on the first entry
1697 bool firstEntry = true;
1698 while (std::getline(logStream, logEntry))
1699 {
1700 std::string idStr;
1701 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001702 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001703 continue;
1704 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001705 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001706
1707 if (idStr == targetID)
1708 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001709 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001710 LogParseError status =
1711 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1712 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001713 {
1714 messages::internalError(asyncResp->res);
1715 return;
1716 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001717 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001718 return;
1719 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001720 }
1721 }
1722 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001723 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05001724 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001725}
1726
1727inline void requestRoutesDBusEventLogEntryCollection(App& app)
1728{
Ed Tanous22d268c2022-05-19 09:39:07 -07001729 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001730 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001731 .methods(boost::beast::http::verb::get)(
1732 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001733 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1734 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001735 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001736 {
1737 return;
1738 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001739 if constexpr (bmcwebEnableMultiHost)
1740 {
1741 // Option currently returns no systems. TBD
1742 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1743 systemName);
1744 return;
1745 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001746 if (systemName != "system")
1747 {
1748 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1749 systemName);
1750 return;
1751 }
1752
Ed Tanous002d39b2022-05-31 08:59:27 -07001753 // Collections don't include the static data added by SubRoute
1754 // because it has a duplicate entry for members
1755 asyncResp->res.jsonValue["@odata.type"] =
1756 "#LogEntryCollection.LogEntryCollection";
1757 asyncResp->res.jsonValue["@odata.id"] =
1758 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1759 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1760 asyncResp->res.jsonValue["Description"] =
1761 "Collection of System Event Log Entries";
1762
1763 // DBus implementation of EventLog/Entries
1764 // Make call to Logging Service to find all log entry objects
George Liu5eb468d2023-06-20 17:03:24 +08001765 sdbusplus::message::object_path path("/xyz/openbmc_project/logging");
1766 dbus::utility::getManagedObjects(
1767 "xyz.openbmc_project.Logging", path,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001768 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001769 const dbus::utility::ManagedObjectType& resp) {
1770 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001771 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001772 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07001773 BMCWEB_LOG_ERROR(
1774 "getLogEntriesIfaceData resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001775 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001776 return;
1777 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001778 nlohmann::json::array_t entriesArray;
Ed Tanous002d39b2022-05-31 08:59:27 -07001779 for (const auto& objectPath : resp)
1780 {
1781 const uint32_t* id = nullptr;
1782 const uint64_t* timestamp = nullptr;
1783 const uint64_t* updateTimestamp = nullptr;
1784 const std::string* severity = nullptr;
1785 const std::string* message = nullptr;
1786 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001787 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001788 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001789 const std::string* notify = nullptr;
1790
Ed Tanous002d39b2022-05-31 08:59:27 -07001791 for (const auto& interfaceMap : objectPath.second)
1792 {
1793 if (interfaceMap.first ==
1794 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001795 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001796 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001797 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001798 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001799 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001800 id = std::get_if<uint32_t>(&propertyMap.second);
1801 }
1802 else if (propertyMap.first == "Timestamp")
1803 {
1804 timestamp =
1805 std::get_if<uint64_t>(&propertyMap.second);
1806 }
1807 else if (propertyMap.first == "UpdateTimestamp")
1808 {
1809 updateTimestamp =
1810 std::get_if<uint64_t>(&propertyMap.second);
1811 }
1812 else if (propertyMap.first == "Severity")
1813 {
1814 severity = std::get_if<std::string>(
1815 &propertyMap.second);
1816 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001817 else if (propertyMap.first == "Resolution")
1818 {
1819 resolution = std::get_if<std::string>(
1820 &propertyMap.second);
1821 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001822 else if (propertyMap.first == "Message")
1823 {
1824 message = std::get_if<std::string>(
1825 &propertyMap.second);
1826 }
1827 else if (propertyMap.first == "Resolved")
1828 {
1829 const bool* resolveptr =
1830 std::get_if<bool>(&propertyMap.second);
1831 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001832 {
1833 messages::internalError(asyncResp->res);
1834 return;
1835 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001836 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001837 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001838 else if (propertyMap.first ==
1839 "ServiceProviderNotify")
1840 {
1841 notify = std::get_if<std::string>(
1842 &propertyMap.second);
1843 if (notify == nullptr)
1844 {
1845 messages::internalError(asyncResp->res);
1846 return;
1847 }
1848 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001849 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001850 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001852 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001853 messages::internalError(asyncResp->res);
1854 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001855 }
1856 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001857 else if (interfaceMap.first ==
1858 "xyz.openbmc_project.Common.FilePath")
1859 {
1860 for (const auto& propertyMap : interfaceMap.second)
1861 {
1862 if (propertyMap.first == "Path")
1863 {
1864 filePath = std::get_if<std::string>(
1865 &propertyMap.second);
1866 }
1867 }
1868 }
1869 }
1870 // Object path without the
1871 // xyz.openbmc_project.Logging.Entry interface, ignore
1872 // and continue.
1873 if (id == nullptr || message == nullptr ||
1874 severity == nullptr || timestamp == nullptr ||
1875 updateTimestamp == nullptr)
1876 {
1877 continue;
1878 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001879 nlohmann::json& thisEntry = entriesArray.emplace_back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001880 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07001881 thisEntry["@odata.id"] = boost::urls::format(
1882 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
1883 std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07001884 thisEntry["Name"] = "System Event Log Entry";
1885 thisEntry["Id"] = std::to_string(*id);
1886 thisEntry["Message"] = *message;
1887 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001888 if ((resolution != nullptr) && (!(*resolution).empty()))
1889 {
1890 thisEntry["Resolution"] = *resolution;
1891 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001892 std::optional<bool> notifyAction =
1893 getProviderNotifyAction(*notify);
1894 if (notifyAction)
1895 {
1896 thisEntry["ServiceProviderNotified"] = *notifyAction;
1897 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001898 thisEntry["EntryType"] = "Event";
1899 thisEntry["Severity"] =
1900 translateSeverityDbusToRedfish(*severity);
1901 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001902 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001903 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001904 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 if (filePath != nullptr)
1906 {
1907 thisEntry["AdditionalDataURI"] =
1908 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1909 std::to_string(*id) + "/attachment";
1910 }
1911 }
Ed Tanous3544d2a2023-08-06 18:12:20 -07001912 std::ranges::sort(entriesArray, [](const nlohmann::json& left,
1913 const nlohmann::json& right) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 return (left["Id"] <= right["Id"]);
Ed Tanous3544d2a2023-08-06 18:12:20 -07001915 });
Ed Tanous002d39b2022-05-31 08:59:27 -07001916 asyncResp->res.jsonValue["Members@odata.count"] =
1917 entriesArray.size();
Ed Tanous3544d2a2023-08-06 18:12:20 -07001918 asyncResp->res.jsonValue["Members"] = std::move(entriesArray);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001919 });
Patrick Williams5a39f772023-10-20 11:20:21 -05001920 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001921}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001922
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001923inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001924{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001925 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001926 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001927 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001928 .methods(boost::beast::http::verb::get)(
1929 [&app](const crow::Request& req,
1930 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001931 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001932 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 {
1934 return;
1935 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08001936 if constexpr (bmcwebEnableMultiHost)
1937 {
1938 // Option currently returns no systems. TBD
1939 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1940 systemName);
1941 return;
1942 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001943 if (systemName != "system")
1944 {
1945 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1946 systemName);
1947 return;
1948 }
1949
Ed Tanous002d39b2022-05-31 08:59:27 -07001950 std::string entryID = param;
1951 dbus::utility::escapePathForDbus(entryID);
1952
1953 // DBus implementation of EventLog/Entries
1954 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001955 sdbusplus::asio::getAllProperties(
1956 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1957 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08001958 [asyncResp, entryID](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 const dbus::utility::DBusPropertiesMap& resp) {
1960 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001961 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001962 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1963 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001964 return;
1965 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001966 if (ec)
1967 {
Ed Tanous62598e32023-07-17 17:06:25 -07001968 BMCWEB_LOG_ERROR(
1969 "EventLogEntry (DBus) resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07001970 messages::internalError(asyncResp->res);
1971 return;
1972 }
1973 const uint32_t* id = nullptr;
1974 const uint64_t* timestamp = nullptr;
1975 const uint64_t* updateTimestamp = nullptr;
1976 const std::string* severity = nullptr;
1977 const std::string* message = nullptr;
1978 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001979 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001980 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001981 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001982
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001983 const bool success = sdbusplus::unpackPropertiesNoThrow(
1984 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1985 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001986 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05001987 "Resolution", resolution, "Path", filePath,
1988 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001989
1990 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001991 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001992 messages::internalError(asyncResp->res);
1993 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001994 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001995
Ed Tanous002d39b2022-05-31 08:59:27 -07001996 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05001997 timestamp == nullptr || updateTimestamp == nullptr ||
1998 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001999 {
2000 messages::internalError(asyncResp->res);
2001 return;
2002 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05002003
Ed Tanous002d39b2022-05-31 08:59:27 -07002004 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05002005 "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002006 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
2007 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/{}",
2008 std::to_string(*id));
Ed Tanous002d39b2022-05-31 08:59:27 -07002009 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
2010 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
2011 asyncResp->res.jsonValue["Message"] = *message;
2012 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05002013 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
2014 if (notifyAction)
2015 {
2016 asyncResp->res.jsonValue["ServiceProviderNotified"] =
2017 *notifyAction;
2018 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05002019 if ((resolution != nullptr) && (!(*resolution).empty()))
2020 {
2021 asyncResp->res.jsonValue["Resolution"] = *resolution;
2022 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002023 asyncResp->res.jsonValue["EntryType"] = "Event";
2024 asyncResp->res.jsonValue["Severity"] =
2025 translateSeverityDbusToRedfish(*severity);
2026 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002027 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002028 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07002029 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002030 if (filePath != nullptr)
2031 {
2032 asyncResp->res.jsonValue["AdditionalDataURI"] =
2033 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
2034 std::to_string(*id) + "/attachment";
2035 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002036 });
Patrick Williams5a39f772023-10-20 11:20:21 -05002037 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002038
2039 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002040 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002041 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002042 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002043 [&app](const crow::Request& req,
2044 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002045 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002046 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002047 {
2048 return;
2049 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002050 if constexpr (bmcwebEnableMultiHost)
2051 {
2052 // Option currently returns no systems. TBD
2053 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2054 systemName);
2055 return;
2056 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002057 if (systemName != "system")
2058 {
2059 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2060 systemName);
2061 return;
2062 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002063 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002064
Ed Tanous002d39b2022-05-31 08:59:27 -07002065 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
2066 resolved))
2067 {
2068 return;
2069 }
Ed Tanous62598e32023-07-17 17:06:25 -07002070 BMCWEB_LOG_DEBUG("Set Resolved");
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002071
Asmitha Karunanithi3eb66652024-04-02 16:34:36 +00002072 setDbusProperty(asyncResp, "xyz.openbmc_project.Logging",
2073 "/xyz/openbmc_project/logging/entry/" + entryId,
2074 "xyz.openbmc_project.Logging.Entry", "Resolved",
2075 "Resolved", *resolved);
Patrick Williams5a39f772023-10-20 11:20:21 -05002076 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06002077
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002078 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002079 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002080 .privileges(redfish::privileges::deleteLogEntry)
2081
Ed Tanous002d39b2022-05-31 08:59:27 -07002082 .methods(boost::beast::http::verb::delete_)(
2083 [&app](const crow::Request& req,
2084 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002085 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002086 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002087 {
2088 return;
2089 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002090 if constexpr (bmcwebEnableMultiHost)
2091 {
2092 // Option currently returns no systems. TBD
2093 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2094 systemName);
2095 return;
2096 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002097 if (systemName != "system")
2098 {
2099 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2100 systemName);
2101 return;
2102 }
Ed Tanous62598e32023-07-17 17:06:25 -07002103 BMCWEB_LOG_DEBUG("Do delete single event entries.");
Ed Tanous002d39b2022-05-31 08:59:27 -07002104
2105 std::string entryID = param;
2106
2107 dbus::utility::escapePathForDbus(entryID);
2108
2109 // Process response from Logging service.
Patrick Williams5a39f772023-10-20 11:20:21 -05002110 auto respHandler = [asyncResp,
2111 entryID](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07002112 BMCWEB_LOG_DEBUG("EventLogEntry (DBus) doDelete callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07002113 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002114 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002115 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002116 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002117 messages::resourceNotFound(asyncResp->res, "LogEntry",
2118 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07002119 return;
2120 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002121 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07002122 BMCWEB_LOG_ERROR(
2123 "EventLogEntry (DBus) doDelete respHandler got error {}",
2124 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07002125 asyncResp->res.result(
2126 boost::beast::http::status::internal_server_error);
2127 return;
2128 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002129
Ed Tanous002d39b2022-05-31 08:59:27 -07002130 asyncResp->res.result(boost::beast::http::status::ok);
2131 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002132
Ed Tanous002d39b2022-05-31 08:59:27 -07002133 // Make call to Logging service to request Delete Log
2134 crow::connections::systemBus->async_method_call(
2135 respHandler, "xyz.openbmc_project.Logging",
2136 "/xyz/openbmc_project/logging/entry/" + entryID,
2137 "xyz.openbmc_project.Object.Delete", "Delete");
Patrick Williams5a39f772023-10-20 11:20:21 -05002138 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002139}
2140
Spencer Kub7028eb2021-10-26 15:27:35 +08002141constexpr const char* hostLoggerFolderPath = "/var/log/console";
2142
2143inline bool
2144 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2145 std::vector<std::filesystem::path>& hostLoggerFiles)
2146{
2147 std::error_code ec;
2148 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2149 if (ec)
2150 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002151 BMCWEB_LOG_WARNING("{}", ec.message());
Spencer Kub7028eb2021-10-26 15:27:35 +08002152 return false;
2153 }
2154 for (const std::filesystem::directory_entry& it : logPath)
2155 {
2156 std::string filename = it.path().filename();
2157 // Prefix of each log files is "log". Find the file and save the
2158 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002159 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002160 {
2161 hostLoggerFiles.emplace_back(it.path());
2162 }
2163 }
2164 // As the log files rotate, they are appended with a ".#" that is higher for
2165 // the older logs. Since we start from oldest logs, sort the name in
2166 // descending order.
2167 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2168 AlphanumLess<std::string>());
2169
2170 return true;
2171}
2172
Ed Tanous02cad962022-06-30 16:50:15 -07002173inline bool getHostLoggerEntries(
2174 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2175 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002176{
2177 GzFileReader logFile;
2178
2179 // Go though all log files and expose host logs.
2180 for (const std::filesystem::path& it : hostLoggerFiles)
2181 {
2182 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2183 {
Ed Tanous62598e32023-07-17 17:06:25 -07002184 BMCWEB_LOG_ERROR("fail to expose host logs");
Spencer Kub7028eb2021-10-26 15:27:35 +08002185 return false;
2186 }
2187 }
2188 // Get lastMessage from constructor by getter
2189 std::string lastMessage = logFile.getLastMessage();
2190 if (!lastMessage.empty())
2191 {
2192 logCount++;
2193 if (logCount > skip && logCount <= (skip + top))
2194 {
2195 logEntries.push_back(lastMessage);
2196 }
2197 }
2198 return true;
2199}
2200
Ed Tanous6f056f22024-04-07 13:35:51 -07002201inline void fillHostLoggerEntryJson(std::string_view logEntryID,
2202 std::string_view msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002203 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002204{
2205 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002206 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002207 logEntryJson["@odata.id"] = boost::urls::format(
2208 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/{}",
2209 logEntryID);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002210 logEntryJson["Name"] = "Host Logger Entry";
2211 logEntryJson["Id"] = logEntryID;
2212 logEntryJson["Message"] = msg;
2213 logEntryJson["EntryType"] = "Oem";
2214 logEntryJson["Severity"] = "OK";
2215 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002216}
2217
2218inline void requestRoutesSystemHostLogger(App& app)
2219{
Ed Tanous22d268c2022-05-19 09:39:07 -07002220 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002221 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002222 .methods(boost::beast::http::verb::get)(
2223 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002224 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2225 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002226 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002227 {
2228 return;
2229 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002230 if constexpr (bmcwebEnableMultiHost)
2231 {
2232 // Option currently returns no systems. TBD
2233 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2234 systemName);
2235 return;
2236 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002237 if (systemName != "system")
2238 {
2239 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2240 systemName);
2241 return;
2242 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002243 asyncResp->res.jsonValue["@odata.id"] =
2244 "/redfish/v1/Systems/system/LogServices/HostLogger";
2245 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002246 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002247 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2248 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2249 asyncResp->res.jsonValue["Id"] = "HostLogger";
2250 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2251 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
Patrick Williams5a39f772023-10-20 11:20:21 -05002252 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002253}
2254
2255inline void requestRoutesSystemHostLoggerCollection(App& app)
2256{
2257 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002258 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002259 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 .methods(boost::beast::http::verb::get)(
2261 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002262 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2263 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002264 query_param::QueryCapabilities capabilities = {
2265 .canDelegateTop = true,
2266 .canDelegateSkip = true,
2267 };
2268 query_param::Query delegatedQuery;
2269 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002270 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002271 {
2272 return;
2273 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002274 if constexpr (bmcwebEnableMultiHost)
2275 {
2276 // Option currently returns no systems. TBD
2277 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2278 systemName);
2279 return;
2280 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002281 if (systemName != "system")
2282 {
2283 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2284 systemName);
2285 return;
2286 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002287 asyncResp->res.jsonValue["@odata.id"] =
2288 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2289 asyncResp->res.jsonValue["@odata.type"] =
2290 "#LogEntryCollection.LogEntryCollection";
2291 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2292 asyncResp->res.jsonValue["Description"] =
2293 "Collection of HostLogger Entries";
2294 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2295 logEntryArray = nlohmann::json::array();
2296 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002297
Ed Tanous002d39b2022-05-31 08:59:27 -07002298 std::vector<std::filesystem::path> hostLoggerFiles;
2299 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2300 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002301 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002302 return;
2303 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002304 // If we weren't provided top and skip limits, use the defaults.
2305 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002306 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002307 size_t logCount = 0;
2308 // This vector only store the entries we want to expose that
2309 // control by skip and top.
2310 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002311 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2312 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002313 {
2314 messages::internalError(asyncResp->res);
2315 return;
2316 }
2317 // If vector is empty, that means skip value larger than total
2318 // log count
2319 if (logEntries.empty())
2320 {
2321 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2322 return;
2323 }
2324 if (!logEntries.empty())
2325 {
2326 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002327 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002328 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002329 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2330 hostLogEntry);
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002331 logEntryArray.emplace_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002332 }
2333
Ed Tanous002d39b2022-05-31 08:59:27 -07002334 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002335 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002336 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002337 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2338 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002339 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002340 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002341 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002342 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002343}
2344
2345inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2346{
2347 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002348 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002349 .privileges(redfish::privileges::getLogEntry)
2350 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002351 [&app](const crow::Request& req,
2352 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002353 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002354 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002355 {
2356 return;
2357 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002358 if constexpr (bmcwebEnableMultiHost)
2359 {
2360 // Option currently returns no systems. TBD
2361 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2362 systemName);
2363 return;
2364 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002365 if (systemName != "system")
2366 {
2367 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2368 systemName);
2369 return;
2370 }
Ed Tanous6f056f22024-04-07 13:35:51 -07002371 std::string_view targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002372
Ed Tanous002d39b2022-05-31 08:59:27 -07002373 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002374
Ed Tanous6f056f22024-04-07 13:35:51 -07002375 auto [ptr, ec] = std::from_chars(targetID.begin(), targetID.end(),
Patrick Williams84396af2023-05-11 11:47:45 -05002376 idInt);
Ed Tanous6f056f22024-04-07 13:35:51 -07002377 if (ec != std::errc{} || ptr != targetID.end())
Ed Tanous002d39b2022-05-31 08:59:27 -07002378 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002379 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002380 return;
2381 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002382
Ed Tanous002d39b2022-05-31 08:59:27 -07002383 std::vector<std::filesystem::path> hostLoggerFiles;
2384 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2385 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002386 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002387 return;
2388 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002389
Ed Tanous002d39b2022-05-31 08:59:27 -07002390 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002391 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002392 std::vector<std::string> logEntries;
2393 // We can get specific entry by skip and top. For example, if we
2394 // want to get nth entry, we can set skip = n-1 and top = 1 to
2395 // get that entry
2396 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2397 logCount))
2398 {
2399 messages::internalError(asyncResp->res);
2400 return;
2401 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002402
Ed Tanous002d39b2022-05-31 08:59:27 -07002403 if (!logEntries.empty())
2404 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002405 nlohmann::json::object_t hostLogEntry;
2406 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2407 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002408 return;
2409 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002410
Ed Tanous002d39b2022-05-31 08:59:27 -07002411 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002412 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Patrick Williams5a39f772023-10-20 11:20:21 -05002413 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002414}
2415
Claire Weinandd72e872022-08-15 14:20:06 -07002416inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002417 crow::App& app, const crow::Request& req,
2418 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2419{
2420 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2421 {
2422 return;
2423 }
2424 // Collections don't include the static data added by SubRoute
2425 // because it has a duplicate entry for members
2426 asyncResp->res.jsonValue["@odata.type"] =
2427 "#LogServiceCollection.LogServiceCollection";
2428 asyncResp->res.jsonValue["@odata.id"] =
2429 "/redfish/v1/Managers/bmc/LogServices";
2430 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2431 asyncResp->res.jsonValue["Description"] =
2432 "Collection of LogServices for this Manager";
2433 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2434 logServiceArray = nlohmann::json::array();
2435
2436#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002437 nlohmann::json::object_t journal;
2438 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002439 logServiceArray.emplace_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002440#endif
2441
2442 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2443
2444#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
George Liu15912152023-01-11 10:18:18 +08002445 constexpr std::array<std::string_view, 1> interfaces = {
George Liu7a1dbc42022-12-07 16:03:22 +08002446 "xyz.openbmc_project.Collection.DeleteAll"};
2447 dbus::utility::getSubTreePaths(
2448 "/xyz/openbmc_project/dump", 0, interfaces,
Claire Weinanfdd26902022-03-01 14:18:25 -08002449 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08002450 const boost::system::error_code& ec,
Claire Weinanfdd26902022-03-01 14:18:25 -08002451 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2452 if (ec)
2453 {
Ed Tanous62598e32023-07-17 17:06:25 -07002454 BMCWEB_LOG_ERROR(
2455 "handleBMCLogServicesCollectionGet respHandler got error {}",
2456 ec);
Claire Weinanfdd26902022-03-01 14:18:25 -08002457 // Assume that getting an error simply means there are no dump
2458 // LogServices. Return without adding any error response.
2459 return;
2460 }
2461
2462 nlohmann::json& logServiceArrayLocal =
2463 asyncResp->res.jsonValue["Members"];
2464
2465 for (const std::string& path : subTreePaths)
2466 {
2467 if (path == "/xyz/openbmc_project/dump/bmc")
2468 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002469 nlohmann::json::object_t member;
2470 member["@odata.id"] =
2471 "/redfish/v1/Managers/bmc/LogServices/Dump";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002472 logServiceArrayLocal.emplace_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002473 }
2474 else if (path == "/xyz/openbmc_project/dump/faultlog")
2475 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002476 nlohmann::json::object_t member;
2477 member["@odata.id"] =
2478 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002479 logServiceArrayLocal.emplace_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002480 }
2481 }
2482
2483 asyncResp->res.jsonValue["Members@odata.count"] =
2484 logServiceArrayLocal.size();
Patrick Williams5a39f772023-10-20 11:20:21 -05002485 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002486#endif
2487}
2488
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002489inline void requestRoutesBMCLogServiceCollection(App& app)
2490{
2491 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002492 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002493 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002494 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002495}
Ed Tanous1da66f72018-07-27 16:13:37 -07002496
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002497inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002498{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002499 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002500 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002501 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002502 [&app](const crow::Request& req,
2503 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002504 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002505 {
2506 return;
2507 }
2508 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002509 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002510 asyncResp->res.jsonValue["@odata.id"] =
2511 "/redfish/v1/Managers/bmc/LogServices/Journal";
2512 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2513 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08002514 asyncResp->res.jsonValue["Id"] = "Journal";
Ed Tanous002d39b2022-05-31 08:59:27 -07002515 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302516
Ed Tanous002d39b2022-05-31 08:59:27 -07002517 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002518 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002519 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2520 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2521 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302522
Ed Tanous002d39b2022-05-31 08:59:27 -07002523 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2524 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Patrick Williams5a39f772023-10-20 11:20:21 -05002525 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002526}
Jason M. Billse1f26342018-07-18 12:12:00 -07002527
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002528static int
2529 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2530 sd_journal* journal,
2531 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002532{
2533 // Get the Log Entry contents
2534 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002535
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002536 std::string message;
2537 std::string_view syslogID;
2538 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2539 if (ret < 0)
2540 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002541 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}",
Ed Tanous62598e32023-07-17 17:06:25 -07002542 strerror(-ret));
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002543 }
2544 if (!syslogID.empty())
2545 {
2546 message += std::string(syslogID) + ": ";
2547 }
2548
Ed Tanous39e77502019-03-04 17:35:53 -08002549 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002550 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002551 if (ret < 0)
2552 {
Ed Tanous62598e32023-07-17 17:06:25 -07002553 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002554 return 1;
2555 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002556 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002557
2558 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002559 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002560 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002561 if (ret < 0)
2562 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002563 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002564 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002565
2566 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002567 std::string entryTimeStr;
2568 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002569 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002570 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002571 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002572
2573 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002574 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002575 bmcJournalLogEntryJson["@odata.id"] = boost::urls::format(
2576 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}",
Willy Tueddfc432022-09-26 16:46:38 +00002577 bmcJournalLogEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07002578 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2579 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2580 bmcJournalLogEntryJson["Message"] = std::move(message);
2581 bmcJournalLogEntryJson["EntryType"] = "Oem";
Ed Tanousddf35642024-03-27 14:12:21 -07002582 log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK;
2583 if (severity <= 2)
2584 {
2585 severityEnum = log_entry::EventSeverity::Critical;
2586 }
2587 else if (severity <= 4)
2588 {
2589 severityEnum = log_entry::EventSeverity::Warning;
2590 }
2591
2592 bmcJournalLogEntryJson["Severity"] = severityEnum;
Jason M. Bills84afc482022-06-24 12:38:23 -07002593 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2594 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002595 return 0;
2596}
2597
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002598inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002599{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002600 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002601 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002602 .methods(boost::beast::http::verb::get)(
2603 [&app](const crow::Request& req,
2604 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2605 query_param::QueryCapabilities capabilities = {
2606 .canDelegateTop = true,
2607 .canDelegateSkip = true,
2608 };
2609 query_param::Query delegatedQuery;
2610 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002611 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002612 {
2613 return;
2614 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002615
2616 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002617 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002618
Ed Tanous002d39b2022-05-31 08:59:27 -07002619 // Collections don't include the static data added by SubRoute
2620 // because it has a duplicate entry for members
2621 asyncResp->res.jsonValue["@odata.type"] =
2622 "#LogEntryCollection.LogEntryCollection";
2623 asyncResp->res.jsonValue["@odata.id"] =
2624 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2625 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2626 asyncResp->res.jsonValue["Description"] =
2627 "Collection of BMC Journal Entries";
2628 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2629 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002630
Ed Tanous002d39b2022-05-31 08:59:27 -07002631 // Go through the journal and use the timestamp to create a
2632 // unique ID for each entry
2633 sd_journal* journalTmp = nullptr;
2634 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2635 if (ret < 0)
2636 {
Ed Tanous62598e32023-07-17 17:06:25 -07002637 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002638 messages::internalError(asyncResp->res);
2639 return;
2640 }
2641 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2642 journalTmp, sd_journal_close);
2643 journalTmp = nullptr;
2644 uint64_t entryCount = 0;
2645 // Reset the unique ID on the first entry
2646 bool firstEntry = true;
2647 SD_JOURNAL_FOREACH(journal.get())
2648 {
2649 entryCount++;
2650 // Handle paging using skip (number of entries to skip from
2651 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002652 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002653 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002654 continue;
2655 }
2656
2657 std::string idStr;
2658 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2659 {
2660 continue;
2661 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002662 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002663
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002664 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002665 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2666 bmcJournalLogEntry) != 0)
2667 {
George Liu0fda0f12021-11-16 10:06:17 +08002668 messages::internalError(asyncResp->res);
2669 return;
2670 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002671 logEntryArray.emplace_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002672 }
2673 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002674 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002675 {
2676 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2677 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002678 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002679 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002680 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002681}
Jason M. Billse1f26342018-07-18 12:12:00 -07002682
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002683inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002684{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002685 BMCWEB_ROUTE(app,
2686 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002687 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002688 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002689 [&app](const crow::Request& req,
2690 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2691 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002692 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002693 {
2694 return;
2695 }
2696 // Convert the unique ID back to a timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -08002697 sd_id128_t bootID{};
Ed Tanous002d39b2022-05-31 08:59:27 -07002698 uint64_t ts = 0;
2699 uint64_t index = 0;
Myung Bae75e8e212023-11-30 12:53:46 -08002700 if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index))
Ed Tanous002d39b2022-05-31 08:59:27 -07002701 {
2702 return;
2703 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002704
Ed Tanous002d39b2022-05-31 08:59:27 -07002705 sd_journal* journalTmp = nullptr;
2706 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2707 if (ret < 0)
2708 {
Ed Tanous62598e32023-07-17 17:06:25 -07002709 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002710 messages::internalError(asyncResp->res);
2711 return;
2712 }
2713 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2714 journalTmp, sd_journal_close);
2715 journalTmp = nullptr;
2716 // Go to the timestamp in the log and move to the entry at the
2717 // index tracking the unique ID
2718 std::string idStr;
2719 bool firstEntry = true;
Myung Bae75e8e212023-11-30 12:53:46 -08002720 ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts);
Ed Tanous002d39b2022-05-31 08:59:27 -07002721 if (ret < 0)
2722 {
Ed Tanous62598e32023-07-17 17:06:25 -07002723 BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}",
2724 strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002725 messages::internalError(asyncResp->res);
2726 return;
2727 }
2728 for (uint64_t i = 0; i <= index; i++)
2729 {
2730 sd_journal_next(journal.get());
2731 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2732 {
2733 messages::internalError(asyncResp->res);
2734 return;
2735 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002736 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002737 }
2738 // Confirm that the entry ID matches what was requested
2739 if (idStr != entryID)
2740 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002741 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002742 return;
2743 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002744
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002745 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002746 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002747 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002748 {
2749 messages::internalError(asyncResp->res);
2750 return;
2751 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002752 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Patrick Williams5a39f772023-10-20 11:20:21 -05002753 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002754}
2755
Claire Weinanfdd26902022-03-01 14:18:25 -08002756inline void
2757 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2758 const std::string& dumpType)
2759{
2760 std::string dumpPath;
2761 std::string overWritePolicy;
2762 bool collectDiagnosticDataSupported = false;
2763
2764 if (dumpType == "BMC")
2765 {
2766 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2767 overWritePolicy = "WrapsWhenFull";
2768 collectDiagnosticDataSupported = true;
2769 }
2770 else if (dumpType == "FaultLog")
2771 {
2772 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2773 overWritePolicy = "Unknown";
2774 collectDiagnosticDataSupported = false;
2775 }
2776 else if (dumpType == "System")
2777 {
2778 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2779 overWritePolicy = "WrapsWhenFull";
2780 collectDiagnosticDataSupported = true;
2781 }
2782 else
2783 {
Ed Tanous62598e32023-07-17 17:06:25 -07002784 BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}",
2785 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -08002786 messages::internalError(asyncResp->res);
2787 return;
2788 }
2789
2790 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2791 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2792 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2793 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2794 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2795 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2796
2797 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002798 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002799 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2800 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2801 redfishDateTimeOffset.second;
2802
2803 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -08002804
2805 if (collectDiagnosticDataSupported)
2806 {
2807 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2808 ["target"] =
2809 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2810 }
Claire Weinan0d946212022-07-13 19:40:19 -07002811
2812 constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface};
2813 dbus::utility::getSubTreePaths(
2814 "/xyz/openbmc_project/dump", 0, interfaces,
2815 [asyncResp, dumpType, dumpPath](
2816 const boost::system::error_code& ec,
2817 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2818 if (ec)
2819 {
Ed Tanous62598e32023-07-17 17:06:25 -07002820 BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec);
Claire Weinan0d946212022-07-13 19:40:19 -07002821 // Assume that getting an error simply means there are no dump
2822 // LogServices. Return without adding any error response.
2823 return;
2824 }
Ed Tanous18f8f602023-07-18 10:07:23 -07002825 std::string dbusDumpPath = getDumpPath(dumpType);
Claire Weinan0d946212022-07-13 19:40:19 -07002826 for (const std::string& path : subTreePaths)
2827 {
2828 if (path == dbusDumpPath)
2829 {
2830 asyncResp->res
2831 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2832 dumpPath + "/Actions/LogService.ClearLog";
2833 break;
2834 }
2835 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002836 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002837}
2838
2839inline void handleLogServicesDumpServiceGet(
2840 crow::App& app, const std::string& dumpType, const crow::Request& req,
2841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2842{
2843 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2844 {
2845 return;
2846 }
2847 getDumpServiceInfo(asyncResp, dumpType);
2848}
2849
Ed Tanous22d268c2022-05-19 09:39:07 -07002850inline void handleLogServicesDumpServiceComputerSystemGet(
2851 crow::App& app, const crow::Request& req,
2852 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2853 const std::string& chassisId)
2854{
2855 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2856 {
2857 return;
2858 }
2859 if (chassisId != "system")
2860 {
2861 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2862 return;
2863 }
2864 getDumpServiceInfo(asyncResp, "System");
2865}
2866
Claire Weinanfdd26902022-03-01 14:18:25 -08002867inline void handleLogServicesDumpEntriesCollectionGet(
2868 crow::App& app, const std::string& dumpType, const crow::Request& req,
2869 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2870{
2871 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2872 {
2873 return;
2874 }
2875 getDumpEntryCollection(asyncResp, dumpType);
2876}
2877
Ed Tanous22d268c2022-05-19 09:39:07 -07002878inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2879 crow::App& app, const crow::Request& req,
2880 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2881 const std::string& chassisId)
2882{
2883 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2884 {
2885 return;
2886 }
2887 if (chassisId != "system")
2888 {
2889 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2890 return;
2891 }
2892 getDumpEntryCollection(asyncResp, "System");
2893}
2894
Claire Weinanfdd26902022-03-01 14:18:25 -08002895inline void handleLogServicesDumpEntryGet(
2896 crow::App& app, const std::string& dumpType, const crow::Request& req,
2897 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2898 const std::string& dumpId)
2899{
2900 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2901 {
2902 return;
2903 }
2904 getDumpEntryById(asyncResp, dumpId, dumpType);
2905}
Carson Labrado168d1b12023-03-27 17:04:46 +00002906
Ed Tanous22d268c2022-05-19 09:39:07 -07002907inline void handleLogServicesDumpEntryComputerSystemGet(
2908 crow::App& app, const crow::Request& req,
2909 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2910 const std::string& chassisId, const std::string& dumpId)
2911{
2912 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2913 {
2914 return;
2915 }
2916 if (chassisId != "system")
2917 {
2918 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2919 return;
2920 }
2921 getDumpEntryById(asyncResp, dumpId, "System");
2922}
Claire Weinanfdd26902022-03-01 14:18:25 -08002923
2924inline void handleLogServicesDumpEntryDelete(
2925 crow::App& app, const std::string& dumpType, const crow::Request& req,
2926 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2927 const std::string& dumpId)
2928{
2929 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2930 {
2931 return;
2932 }
2933 deleteDumpEntry(asyncResp, dumpId, dumpType);
2934}
2935
Ed Tanous22d268c2022-05-19 09:39:07 -07002936inline void handleLogServicesDumpEntryComputerSystemDelete(
2937 crow::App& app, const crow::Request& req,
2938 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2939 const std::string& chassisId, const std::string& dumpId)
2940{
2941 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2942 {
2943 return;
2944 }
2945 if (chassisId != "system")
2946 {
2947 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2948 return;
2949 }
2950 deleteDumpEntry(asyncResp, dumpId, "System");
2951}
2952
Carson Labrado168d1b12023-03-27 17:04:46 +00002953inline void handleLogServicesDumpEntryDownloadGet(
2954 crow::App& app, const std::string& dumpType, const crow::Request& req,
2955 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2956 const std::string& dumpId)
2957{
2958 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2959 {
2960 return;
2961 }
2962 downloadDumpEntry(asyncResp, dumpId, dumpType);
2963}
2964
2965inline void handleDBusEventLogEntryDownloadGet(
2966 crow::App& app, const std::string& dumpType, const crow::Request& req,
2967 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2968 const std::string& systemName, const std::string& entryID)
2969{
2970 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2971 {
2972 return;
2973 }
2974 if (!http_helpers::isContentTypeAllowed(
2975 req.getHeaderValue("Accept"),
2976 http_helpers::ContentType::OctetStream, true))
2977 {
2978 asyncResp->res.result(boost::beast::http::status::bad_request);
2979 return;
2980 }
2981 downloadEventLogEntry(asyncResp, systemName, entryID, dumpType);
2982}
2983
Claire Weinanfdd26902022-03-01 14:18:25 -08002984inline void handleLogServicesDumpCollectDiagnosticDataPost(
2985 crow::App& app, const std::string& dumpType, const crow::Request& req,
2986 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2987{
2988 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2989 {
2990 return;
2991 }
2992 createDump(asyncResp, req, dumpType);
2993}
2994
Ed Tanous22d268c2022-05-19 09:39:07 -07002995inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2996 crow::App& app, const crow::Request& req,
2997 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002998 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07002999{
3000 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3001 {
3002 return;
3003 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003004
3005 if constexpr (bmcwebEnableMultiHost)
Ed Tanous22d268c2022-05-19 09:39:07 -07003006 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003007 // Option currently returns no systems. TBD
3008 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3009 systemName);
3010 return;
3011 }
3012 if (systemName != "system")
3013 {
3014 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3015 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003016 return;
3017 }
3018 createDump(asyncResp, req, "System");
3019}
3020
Claire Weinanfdd26902022-03-01 14:18:25 -08003021inline void handleLogServicesDumpClearLogPost(
3022 crow::App& app, const std::string& dumpType, const crow::Request& req,
3023 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3024{
3025 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3026 {
3027 return;
3028 }
3029 clearDump(asyncResp, dumpType);
3030}
3031
Ed Tanous22d268c2022-05-19 09:39:07 -07003032inline void handleLogServicesDumpClearLogComputerSystemPost(
3033 crow::App& app, const crow::Request& req,
3034 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003035 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003036{
3037 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3038 {
3039 return;
3040 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003041 if constexpr (bmcwebEnableMultiHost)
Ed Tanous22d268c2022-05-19 09:39:07 -07003042 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003043 // Option currently returns no systems. TBD
3044 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3045 systemName);
3046 return;
3047 }
3048 if (systemName != "system")
3049 {
3050 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3051 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003052 return;
3053 }
3054 clearDump(asyncResp, "System");
3055}
3056
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003057inline void requestRoutesBMCDumpService(App& app)
3058{
3059 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003060 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003061 .methods(boost::beast::http::verb::get)(std::bind_front(
3062 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003063}
3064
3065inline void requestRoutesBMCDumpEntryCollection(App& app)
3066{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003067 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003068 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08003069 .methods(boost::beast::http::verb::get)(std::bind_front(
3070 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003071}
3072
3073inline void requestRoutesBMCDumpEntry(App& app)
3074{
3075 BMCWEB_ROUTE(app,
3076 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003077 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003078 .methods(boost::beast::http::verb::get)(std::bind_front(
3079 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
3080
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003081 BMCWEB_ROUTE(app,
3082 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003083 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003084 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3085 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003086}
3087
Carson Labrado168d1b12023-03-27 17:04:46 +00003088inline void requestRoutesBMCDumpEntryDownload(App& app)
3089{
3090 BMCWEB_ROUTE(
3091 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003092 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003093 .privileges(redfish::privileges::getLogEntry)
3094 .methods(boost::beast::http::verb::get)(std::bind_front(
3095 handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC"));
3096}
3097
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003098inline void requestRoutesBMCDumpCreate(App& app)
3099{
George Liu0fda0f12021-11-16 10:06:17 +08003100 BMCWEB_ROUTE(
3101 app,
3102 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003103 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003104 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08003105 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
3106 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003107}
3108
3109inline void requestRoutesBMCDumpClear(App& app)
3110{
George Liu0fda0f12021-11-16 10:06:17 +08003111 BMCWEB_ROUTE(
3112 app,
3113 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003114 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003115 .methods(boost::beast::http::verb::post)(std::bind_front(
3116 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
3117}
3118
Carson Labrado168d1b12023-03-27 17:04:46 +00003119inline void requestRoutesDBusEventLogEntryDownload(App& app)
3120{
3121 BMCWEB_ROUTE(
3122 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003123 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003124 .privileges(redfish::privileges::getLogEntry)
3125 .methods(boost::beast::http::verb::get)(std::bind_front(
3126 handleDBusEventLogEntryDownloadGet, std::ref(app), "System"));
3127}
3128
Claire Weinanfdd26902022-03-01 14:18:25 -08003129inline void requestRoutesFaultLogDumpService(App& app)
3130{
3131 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
3132 .privileges(redfish::privileges::getLogService)
3133 .methods(boost::beast::http::verb::get)(std::bind_front(
3134 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
3135}
3136
3137inline void requestRoutesFaultLogDumpEntryCollection(App& app)
3138{
3139 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
3140 .privileges(redfish::privileges::getLogEntryCollection)
3141 .methods(boost::beast::http::verb::get)(
3142 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
3143 std::ref(app), "FaultLog"));
3144}
3145
3146inline void requestRoutesFaultLogDumpEntry(App& app)
3147{
3148 BMCWEB_ROUTE(app,
3149 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3150 .privileges(redfish::privileges::getLogEntry)
3151 .methods(boost::beast::http::verb::get)(std::bind_front(
3152 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
3153
3154 BMCWEB_ROUTE(app,
3155 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3156 .privileges(redfish::privileges::deleteLogEntry)
3157 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3158 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
3159}
3160
3161inline void requestRoutesFaultLogDumpClear(App& app)
3162{
3163 BMCWEB_ROUTE(
3164 app,
3165 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
3166 .privileges(redfish::privileges::postLogService)
3167 .methods(boost::beast::http::verb::post)(std::bind_front(
3168 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003169}
3170
3171inline void requestRoutesSystemDumpService(App& app)
3172{
Ed Tanous22d268c2022-05-19 09:39:07 -07003173 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003174 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003175 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003176 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003177}
3178
3179inline void requestRoutesSystemDumpEntryCollection(App& app)
3180{
Ed Tanous22d268c2022-05-19 09:39:07 -07003181 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003182 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07003183 .methods(boost::beast::http::verb::get)(std::bind_front(
3184 handleLogServicesDumpEntriesCollectionComputerSystemGet,
3185 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003186}
3187
3188inline void requestRoutesSystemDumpEntry(App& app)
3189{
3190 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003191 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003192 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003193 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003194 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003195
3196 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003197 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003198 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003199 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003200 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003201}
3202
3203inline void requestRoutesSystemDumpCreate(App& app)
3204{
George Liu0fda0f12021-11-16 10:06:17 +08003205 BMCWEB_ROUTE(
3206 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003207 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003208 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07003209 .methods(boost::beast::http::verb::post)(std::bind_front(
3210 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
3211 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003212}
3213
3214inline void requestRoutesSystemDumpClear(App& app)
3215{
George Liu0fda0f12021-11-16 10:06:17 +08003216 BMCWEB_ROUTE(
3217 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003218 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003219 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003220 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003221 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003222}
3223
3224inline void requestRoutesCrashdumpService(App& app)
3225{
3226 // Note: Deviated from redfish privilege registry for GET & HEAD
3227 // method for security reasons.
3228 /**
3229 * Functions triggers appropriate requests on DBus
3230 */
Ed Tanous22d268c2022-05-19 09:39:07 -07003231 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07003232 // This is incorrect, should be:
3233 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003234 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003235 .methods(boost::beast::http::verb::get)(
3236 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003237 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3238 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003239 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003240 {
3241 return;
3242 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003243 if constexpr (bmcwebEnableMultiHost)
3244 {
3245 // Option currently returns no systems. TBD
3246 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3247 systemName);
3248 return;
3249 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003250 if (systemName != "system")
3251 {
3252 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3253 systemName);
3254 return;
3255 }
3256
Ed Tanous002d39b2022-05-31 08:59:27 -07003257 // Copy over the static data to include the entries added by
3258 // SubRoute
3259 asyncResp->res.jsonValue["@odata.id"] =
3260 "/redfish/v1/Systems/system/LogServices/Crashdump";
3261 asyncResp->res.jsonValue["@odata.type"] =
3262 "#LogService.v1_2_0.LogService";
3263 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3264 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
V-Sanjana15b89722023-05-11 16:27:03 +05303265 asyncResp->res.jsonValue["Id"] = "Crashdump";
Ed Tanous002d39b2022-05-31 08:59:27 -07003266 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3267 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303268
Ed Tanous002d39b2022-05-31 08:59:27 -07003269 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003270 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003271 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3272 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3273 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303274
Ed Tanous002d39b2022-05-31 08:59:27 -07003275 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -07003276 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Ed Tanous002d39b2022-05-31 08:59:27 -07003277 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
3278 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
3279 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
3280 ["target"] =
3281 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
Patrick Williams5a39f772023-10-20 11:20:21 -05003282 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003283}
3284
3285void inline requestRoutesCrashdumpClear(App& app)
3286{
George Liu0fda0f12021-11-16 10:06:17 +08003287 BMCWEB_ROUTE(
3288 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003289 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003290 // This is incorrect, should be:
3291 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003292 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003293 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003294 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003295 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3296 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003297 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003298 {
3299 return;
3300 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003301 if constexpr (bmcwebEnableMultiHost)
3302 {
3303 // Option currently returns no systems. TBD
3304 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3305 systemName);
3306 return;
3307 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003308 if (systemName != "system")
3309 {
3310 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3311 systemName);
3312 return;
3313 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003314 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003315 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003316 const std::string&) {
3317 if (ec)
3318 {
3319 messages::internalError(asyncResp->res);
3320 return;
3321 }
3322 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003323 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003324 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003325 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003326}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003327
zhanghch058d1b46d2021-04-01 11:18:24 +08003328static void
3329 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3330 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003331{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003332 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003333 [asyncResp, logID,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003334 &logEntryJson](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08003335 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003336 if (ec)
3337 {
Ed Tanous62598e32023-07-17 17:06:25 -07003338 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003339 if (ec.value() ==
3340 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003341 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003342 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003343 }
3344 else
3345 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003346 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003347 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003348 return;
3349 }
3350
3351 std::string timestamp{};
3352 std::string filename{};
3353 std::string logfile{};
3354 parseCrashdumpParameters(params, filename, timestamp, logfile);
3355
3356 if (filename.empty() || timestamp.empty())
3357 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003358 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003359 return;
3360 }
3361
3362 std::string crashdumpURI =
3363 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3364 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003365 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003366 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07003367 logEntry["@odata.id"] = boost::urls::format(
3368 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}",
3369 logID);
Jason M. Bills84afc482022-06-24 12:38:23 -07003370 logEntry["Name"] = "CPU Crashdump";
3371 logEntry["Id"] = logID;
3372 logEntry["EntryType"] = "Oem";
3373 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3374 logEntry["DiagnosticDataType"] = "OEM";
3375 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3376 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003377
3378 // If logEntryJson references an array of LogEntry resources
3379 // ('Members' list), then push this as a new entry, otherwise set it
3380 // directly
3381 if (logEntryJson.is_array())
3382 {
3383 logEntryJson.push_back(logEntry);
3384 asyncResp->res.jsonValue["Members@odata.count"] =
3385 logEntryJson.size();
3386 }
3387 else
3388 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003389 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003390 }
3391 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003392 sdbusplus::asio::getAllProperties(
3393 *crow::connections::systemBus, crashdumpObject,
3394 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3395 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003396}
3397
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003398inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003399{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003400 // Note: Deviated from redfish privilege registry for GET & HEAD
3401 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003402 /**
3403 * Functions triggers appropriate requests on DBus
3404 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003405 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003406 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003407 // This is incorrect, should be.
3408 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003409 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003410 .methods(boost::beast::http::verb::get)(
3411 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003412 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3413 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003414 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003415 {
3416 return;
3417 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003418 if constexpr (bmcwebEnableMultiHost)
3419 {
3420 // Option currently returns no systems. TBD
3421 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3422 systemName);
3423 return;
3424 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003425 if (systemName != "system")
3426 {
3427 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3428 systemName);
3429 return;
3430 }
3431
George Liu7a1dbc42022-12-07 16:03:22 +08003432 constexpr std::array<std::string_view, 1> interfaces = {
3433 crashdumpInterface};
3434 dbus::utility::getSubTreePaths(
3435 "/", 0, interfaces,
3436 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003437 const std::vector<std::string>& resp) {
3438 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003439 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003440 if (ec.value() !=
3441 boost::system::errc::no_such_file_or_directory)
3442 {
Ed Tanous62598e32023-07-17 17:06:25 -07003443 BMCWEB_LOG_DEBUG("failed to get entries ec: {}",
3444 ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003445 messages::internalError(asyncResp->res);
3446 return;
3447 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003448 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003449 asyncResp->res.jsonValue["@odata.type"] =
3450 "#LogEntryCollection.LogEntryCollection";
3451 asyncResp->res.jsonValue["@odata.id"] =
3452 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3453 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3454 asyncResp->res.jsonValue["Description"] =
3455 "Collection of Crashdump Entries";
3456 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3457 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003458
Ed Tanous002d39b2022-05-31 08:59:27 -07003459 for (const std::string& path : resp)
3460 {
3461 const sdbusplus::message::object_path objPath(path);
3462 // Get the log ID
3463 std::string logID = objPath.filename();
3464 if (logID.empty())
3465 {
3466 continue;
3467 }
3468 // Add the log entry to the array
3469 logCrashdumpEntry(asyncResp, logID,
3470 asyncResp->res.jsonValue["Members"]);
3471 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003472 });
Patrick Williams5a39f772023-10-20 11:20:21 -05003473 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003474}
Ed Tanous1da66f72018-07-27 16:13:37 -07003475
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003476inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003477{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003478 // Note: Deviated from redfish privilege registry for GET & HEAD
3479 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003480
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003481 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003482 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003483 // this is incorrect, should be
3484 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003485 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003486 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003487 [&app](const crow::Request& req,
3488 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003489 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003490 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003491 {
3492 return;
3493 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003494 if constexpr (bmcwebEnableMultiHost)
3495 {
3496 // Option currently returns no systems. TBD
3497 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3498 systemName);
3499 return;
3500 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003501 if (systemName != "system")
3502 {
3503 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3504 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003505 return;
3506 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003507 const std::string& logID = param;
3508 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
Patrick Williams5a39f772023-10-20 11:20:21 -05003509 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003510}
Ed Tanous1da66f72018-07-27 16:13:37 -07003511
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003512inline void requestRoutesCrashdumpFile(App& app)
3513{
3514 // Note: Deviated from redfish privilege registry for GET & HEAD
3515 // method for security reasons.
3516 BMCWEB_ROUTE(
3517 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003518 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003519 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003520 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003521 [](const crow::Request& req,
3522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003523 const std::string& systemName, const std::string& logID,
3524 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003525 // Do not call getRedfishRoute here since the crashdump file is not a
3526 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003527
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003528 if constexpr (bmcwebEnableMultiHost)
3529 {
3530 // Option currently returns no systems. TBD
3531 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3532 systemName);
3533 return;
3534 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003535 if (systemName != "system")
3536 {
3537 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3538 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003539 return;
3540 }
3541
Ed Tanous002d39b2022-05-31 08:59:27 -07003542 auto getStoredLogCallback =
Ed Tanous39662a32023-02-06 15:09:46 -08003543 [asyncResp, logID, fileName, url(boost::urls::url(req.url()))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003544 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003545 const std::vector<
3546 std::pair<std::string, dbus::utility::DbusVariantType>>&
3547 resp) {
3548 if (ec)
3549 {
Ed Tanous62598e32023-07-17 17:06:25 -07003550 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003551 messages::internalError(asyncResp->res);
3552 return;
3553 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003554
Ed Tanous002d39b2022-05-31 08:59:27 -07003555 std::string dbusFilename{};
3556 std::string dbusTimestamp{};
3557 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003558
Ed Tanous002d39b2022-05-31 08:59:27 -07003559 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3560 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003561
Ed Tanous002d39b2022-05-31 08:59:27 -07003562 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3563 dbusFilepath.empty())
3564 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003565 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003566 return;
3567 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003568
Ed Tanous002d39b2022-05-31 08:59:27 -07003569 // Verify the file name parameter is correct
3570 if (fileName != dbusFilename)
3571 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003572 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003573 return;
3574 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003575
Ed Tanous27b0cf92023-08-07 12:02:40 -07003576 if (!asyncResp->res.openFile(dbusFilepath))
Ed Tanous002d39b2022-05-31 08:59:27 -07003577 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003578 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003579 return;
3580 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003581
Ed Tanous002d39b2022-05-31 08:59:27 -07003582 // Configure this to be a file download when accessed
3583 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003584 asyncResp->res.addHeader(
3585 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003586 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003587 sdbusplus::asio::getAllProperties(
3588 *crow::connections::systemBus, crashdumpObject,
3589 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3590 std::move(getStoredLogCallback));
Patrick Williams5a39f772023-10-20 11:20:21 -05003591 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003592}
3593
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003594enum class OEMDiagnosticType
3595{
3596 onDemand,
3597 telemetry,
3598 invalid,
3599};
3600
Ed Tanous26ccae32023-02-16 10:28:44 -08003601inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003602{
3603 if (oemDiagStr == "OnDemand")
3604 {
3605 return OEMDiagnosticType::onDemand;
3606 }
3607 if (oemDiagStr == "Telemetry")
3608 {
3609 return OEMDiagnosticType::telemetry;
3610 }
3611
3612 return OEMDiagnosticType::invalid;
3613}
3614
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003615inline void requestRoutesCrashdumpCollect(App& app)
3616{
3617 // Note: Deviated from redfish privilege registry for GET & HEAD
3618 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003619 BMCWEB_ROUTE(
3620 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003621 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003622 // The below is incorrect; Should be ConfigureManager
3623 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003624 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003625 .methods(boost::beast::http::verb::post)(
3626 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003627 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3628 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003629 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003630 {
3631 return;
3632 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003633
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003634 if constexpr (bmcwebEnableMultiHost)
3635 {
3636 // Option currently returns no systems. TBD
3637 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3638 systemName);
3639 return;
3640 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003641 if (systemName != "system")
3642 {
3643 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3644 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003645 return;
3646 }
3647
Ed Tanous002d39b2022-05-31 08:59:27 -07003648 std::string diagnosticDataType;
3649 std::string oemDiagnosticDataType;
3650 if (!redfish::json_util::readJsonAction(
3651 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3652 "OEMDiagnosticDataType", oemDiagnosticDataType))
3653 {
3654 return;
3655 }
3656
3657 if (diagnosticDataType != "OEM")
3658 {
Ed Tanous62598e32023-07-17 17:06:25 -07003659 BMCWEB_LOG_ERROR(
3660 "Only OEM DiagnosticDataType supported for Crashdump");
Ed Tanous002d39b2022-05-31 08:59:27 -07003661 messages::actionParameterValueFormatError(
3662 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3663 "CollectDiagnosticData");
3664 return;
3665 }
3666
3667 OEMDiagnosticType oemDiagType =
3668 getOEMDiagnosticType(oemDiagnosticDataType);
3669
3670 std::string iface;
3671 std::string method;
3672 std::string taskMatchStr;
3673 if (oemDiagType == OEMDiagnosticType::onDemand)
3674 {
3675 iface = crashdumpOnDemandInterface;
3676 method = "GenerateOnDemandLog";
3677 taskMatchStr = "type='signal',"
3678 "interface='org.freedesktop.DBus.Properties',"
3679 "member='PropertiesChanged',"
3680 "arg0namespace='com.intel.crashdump'";
3681 }
3682 else if (oemDiagType == OEMDiagnosticType::telemetry)
3683 {
3684 iface = crashdumpTelemetryInterface;
3685 method = "GenerateTelemetryLog";
3686 taskMatchStr = "type='signal',"
3687 "interface='org.freedesktop.DBus.Properties',"
3688 "member='PropertiesChanged',"
3689 "arg0namespace='com.intel.crashdump'";
3690 }
3691 else
3692 {
Ed Tanous62598e32023-07-17 17:06:25 -07003693 BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}",
3694 oemDiagnosticDataType);
Ed Tanous002d39b2022-05-31 08:59:27 -07003695 messages::actionParameterValueFormatError(
3696 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3697 "CollectDiagnosticData");
3698 return;
3699 }
3700
3701 auto collectCrashdumpCallback =
3702 [asyncResp, payload(task::Payload(req)),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003703 taskMatchStr](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003704 const std::string&) mutable {
3705 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003706 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003707 if (ec.value() == boost::system::errc::operation_not_supported)
3708 {
3709 messages::resourceInStandby(asyncResp->res);
3710 }
3711 else if (ec.value() ==
3712 boost::system::errc::device_or_resource_busy)
3713 {
3714 messages::serviceTemporarilyUnavailable(asyncResp->res,
3715 "60");
3716 }
3717 else
3718 {
3719 messages::internalError(asyncResp->res);
3720 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003721 return;
3722 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003723 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Ed Tanous8b242752023-06-27 17:17:13 -07003724 [](const boost::system::error_code& ec2, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003725 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07003726 if (!ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -07003727 {
3728 taskData->messages.emplace_back(messages::taskCompletedOK(
3729 std::to_string(taskData->index)));
3730 taskData->state = "Completed";
3731 }
3732 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05003733 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003734 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003735
Ed Tanous002d39b2022-05-31 08:59:27 -07003736 task->startTimer(std::chrono::minutes(5));
3737 task->populateResp(asyncResp->res);
3738 task->payload.emplace(std::move(payload));
3739 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003740
Ed Tanous002d39b2022-05-31 08:59:27 -07003741 crow::connections::systemBus->async_method_call(
3742 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3743 iface, method);
Patrick Williams5a39f772023-10-20 11:20:21 -05003744 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003745}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003746
Andrew Geisslercb92c032018-08-17 07:56:14 -07003747/**
3748 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3749 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003750inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003751{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003752 /**
3753 * Function handles POST method request.
3754 * The Clear Log actions does not require any parameter.The action deletes
3755 * all entries found in the Entries collection for this Log Service.
3756 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003757
George Liu0fda0f12021-11-16 10:06:17 +08003758 BMCWEB_ROUTE(
3759 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003760 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003761 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003762 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003763 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003764 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3765 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003766 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003767 {
3768 return;
3769 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003770 if constexpr (bmcwebEnableMultiHost)
3771 {
3772 // Option currently returns no systems. TBD
3773 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3774 systemName);
3775 return;
3776 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003777 if (systemName != "system")
3778 {
3779 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3780 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003781 return;
3782 }
Ed Tanous62598e32023-07-17 17:06:25 -07003783 BMCWEB_LOG_DEBUG("Do delete all entries.");
Andrew Geisslercb92c032018-08-17 07:56:14 -07003784
Ed Tanous002d39b2022-05-31 08:59:27 -07003785 // Process response from Logging service.
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003786 auto respHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07003787 BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07003788 if (ec)
3789 {
3790 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003791 BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003792 asyncResp->res.result(
3793 boost::beast::http::status::internal_server_error);
3794 return;
3795 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003796
Ed Tanous002d39b2022-05-31 08:59:27 -07003797 asyncResp->res.result(boost::beast::http::status::no_content);
3798 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003799
Ed Tanous002d39b2022-05-31 08:59:27 -07003800 // Make call to Logging service to request Clear Log
3801 crow::connections::systemBus->async_method_call(
3802 respHandler, "xyz.openbmc_project.Logging",
3803 "/xyz/openbmc_project/logging",
3804 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003805 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003806}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003807
3808/****************************************************
3809 * Redfish PostCode interfaces
3810 * using DBUS interface: getPostCodesTS
3811 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003812inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003813{
Ed Tanous22d268c2022-05-19 09:39:07 -07003814 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003815 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003816 .methods(boost::beast::http::verb::get)(
3817 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003818 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3819 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003820 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003821 {
3822 return;
3823 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003824 if constexpr (bmcwebEnableMultiHost)
3825 {
3826 // Option currently returns no systems. TBD
3827 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3828 systemName);
3829 return;
3830 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003831 if (systemName != "system")
3832 {
3833 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3834 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003835 return;
3836 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003837 asyncResp->res.jsonValue["@odata.id"] =
3838 "/redfish/v1/Systems/system/LogServices/PostCodes";
3839 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05003840 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07003841 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3842 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08003843 asyncResp->res.jsonValue["Id"] = "PostCodes";
Ed Tanous002d39b2022-05-31 08:59:27 -07003844 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3845 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3846 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303847
Ed Tanous002d39b2022-05-31 08:59:27 -07003848 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003849 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003850 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3851 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3852 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303853
Ed Tanous002d39b2022-05-31 08:59:27 -07003854 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3855 {"target",
3856 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
Patrick Williams5a39f772023-10-20 11:20:21 -05003857 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003858}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003859
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003860inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003861{
George Liu0fda0f12021-11-16 10:06:17 +08003862 BMCWEB_ROUTE(
3863 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003864 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003865 // The following privilege is incorrect; It should be ConfigureManager
3866 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003867 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003868 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003869 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003870 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3871 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003872 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003873 {
3874 return;
3875 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003876 if constexpr (bmcwebEnableMultiHost)
3877 {
3878 // Option currently returns no systems. TBD
3879 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3880 systemName);
3881 return;
3882 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003883 if (systemName != "system")
3884 {
3885 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3886 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003887 return;
3888 }
Ed Tanous62598e32023-07-17 17:06:25 -07003889 BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003890
Ed Tanous002d39b2022-05-31 08:59:27 -07003891 // Make call to post-code service to request clear all
3892 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003893 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003894 if (ec)
3895 {
3896 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003897 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
3898 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003899 asyncResp->res.result(
3900 boost::beast::http::status::internal_server_error);
3901 messages::internalError(asyncResp->res);
3902 return;
3903 }
Tony Lee18fc70c2023-08-24 16:15:54 +08003904 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003905 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003906 "xyz.openbmc_project.State.Boot.PostCode0",
3907 "/xyz/openbmc_project/State/Boot/PostCode0",
3908 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003909 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003910}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003911
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003912/**
3913 * @brief Parse post code ID and get the current value and index value
3914 * eg: postCodeID=B1-2, currentValue=1, index=2
3915 *
3916 * @param[in] postCodeID Post Code ID
3917 * @param[out] currentValue Current value
3918 * @param[out] index Index value
3919 *
3920 * @return bool true if the parsing is successful, false the parsing fails
3921 */
Ed Tanous6f056f22024-04-07 13:35:51 -07003922inline bool parsePostCode(std::string_view postCodeID, uint64_t& currentValue,
Ed Tanousdf254f22024-04-01 13:25:46 -07003923 uint16_t& index)
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003924{
3925 std::vector<std::string> split;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08003926 bmcweb::split(split, postCodeID, '-');
Ed Tanous6f056f22024-04-07 13:35:51 -07003927 if (split.size() != 2)
3928 {
3929 return false;
3930 }
3931 std::string_view postCodeNumber = split[0];
3932 if (postCodeNumber.size() < 2)
3933 {
3934 return false;
3935 }
3936 if (postCodeNumber[0] != 'B')
3937 {
3938 return false;
3939 }
3940 postCodeNumber.remove_prefix(1);
3941 auto [ptrIndex, ecIndex] = std::from_chars(postCodeNumber.begin(),
3942 postCodeNumber.end(), index);
3943 if (ptrIndex != postCodeNumber.end() || ecIndex != std::errc())
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003944 {
3945 return false;
3946 }
3947
Ed Tanous6f056f22024-04-07 13:35:51 -07003948 std::string_view postCodeIndex = split[1];
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003949
Ed Tanous6f056f22024-04-07 13:35:51 -07003950 auto [ptrValue, ecValue] = std::from_chars(
3951 postCodeIndex.begin(), postCodeIndex.end(), currentValue);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003952
Ed Tanous6f056f22024-04-07 13:35:51 -07003953 return ptrValue == postCodeIndex.end() && ecValue == std::errc();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003954}
3955
3956static bool fillPostCodeEntry(
Ed Tanousac106bf2023-06-07 09:24:59 -07003957 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303958 const boost::container::flat_map<
3959 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003960 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3961 const uint64_t skip = 0, const uint64_t top = 0)
3962{
3963 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003964 const registries::Message* message =
3965 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
Ed Tanousdc8cfa62024-04-07 13:37:25 -07003966 if (message == nullptr)
3967 {
3968 BMCWEB_LOG_ERROR("Couldn't find known message?");
3969 return false;
3970 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003971 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003972 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303973 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3974 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003975 {
3976 currentCodeIndex++;
3977 std::string postcodeEntryID =
3978 "B" + std::to_string(bootIndex) + "-" +
3979 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3980
3981 uint64_t usecSinceEpoch = code.first;
3982 uint64_t usTimeOffset = 0;
3983
3984 if (1 == currentCodeIndex)
3985 { // already incremented
3986 firstCodeTimeUs = code.first;
3987 }
3988 else
3989 {
3990 usTimeOffset = code.first - firstCodeTimeUs;
3991 }
3992
3993 // skip if no specific codeIndex is specified and currentCodeIndex does
3994 // not fall between top and skip
3995 if ((codeIndex == 0) &&
3996 (currentCodeIndex <= skip || currentCodeIndex > top))
3997 {
3998 continue;
3999 }
4000
Gunnar Mills4e0453b2020-07-08 14:00:30 -05004001 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08004002 // currentIndex
4003 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
4004 {
4005 // This is done for simplicity. 1st entry is needed to calculate
4006 // time offset. To improve efficiency, one can get to the entry
4007 // directly (possibly with flatmap's nth method)
4008 continue;
4009 }
4010
4011 // currentCodeIndex is within top and skip or equal to specified code
4012 // index
4013
4014 // Get the Created time from the timestamp
4015 std::string entryTimeStr;
Konstantin Aladyshev2a025612023-02-15 11:52:58 +03004016 entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004017
4018 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
4019 std::ostringstream hexCode;
4020 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304021 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004022 std::ostringstream timeOffsetStr;
4023 // Set Fixed -Point Notation
4024 timeOffsetStr << std::fixed;
4025 // Set precision to 4 digits
4026 timeOffsetStr << std::setprecision(4);
4027 // Add double to stream
4028 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004029
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004030 std::string bootIndexStr = std::to_string(bootIndex);
4031 std::string timeOffsetString = timeOffsetStr.str();
4032 std::string hexCodeStr = hexCode.str();
4033
4034 std::array<std::string_view, 3> messageArgs = {
4035 bootIndexStr, timeOffsetString, hexCodeStr};
4036
4037 std::string msg =
4038 redfish::registries::fillMessageArgs(messageArgs, message->message);
4039 if (msg.empty())
ZhikuiRena3316fc2020-01-29 14:58:08 -08004040 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004041 messages::internalError(asyncResp->res);
4042 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004043 }
4044
Tim Leed4342a92020-04-27 11:47:58 +08004045 // Get Severity template from message registry
4046 std::string severity;
4047 if (message != nullptr)
4048 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08004049 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08004050 }
4051
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004052 // Format entry
4053 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05004054 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07004055 bmcLogEntry["@odata.id"] = boost::urls::format(
4056 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}",
4057 postcodeEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07004058 bmcLogEntry["Name"] = "POST Code Log Entry";
4059 bmcLogEntry["Id"] = postcodeEntryID;
4060 bmcLogEntry["Message"] = std::move(msg);
4061 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004062 bmcLogEntry["MessageArgs"] = messageArgs;
Jason M. Bills84afc482022-06-24 12:38:23 -07004063 bmcLogEntry["EntryType"] = "Event";
4064 bmcLogEntry["Severity"] = std::move(severity);
4065 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08004066 if (!std::get<std::vector<uint8_t>>(code.second).empty())
4067 {
4068 bmcLogEntry["AdditionalDataURI"] =
4069 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
4070 postcodeEntryID + "/attachment";
4071 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004072
4073 // codeIndex is only specified when querying single entry, return only
4074 // that entry in this case
4075 if (codeIndex != 0)
4076 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004077 asyncResp->res.jsonValue.update(bmcLogEntry);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004078 return true;
4079 }
4080
Ed Tanousac106bf2023-06-07 09:24:59 -07004081 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Patrick Williamsb2ba3072023-05-12 10:27:39 -05004082 logEntryArray.emplace_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08004083 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004084
4085 // Return value is always false when querying multiple entries
4086 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004087}
4088
Ed Tanousac106bf2023-06-07 09:24:59 -07004089static void
4090 getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4091 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004092{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004093 uint16_t bootIndex = 0;
4094 uint64_t codeIndex = 0;
4095 if (!parsePostCode(entryId, codeIndex, bootIndex))
4096 {
4097 // Requested ID was not found
Ed Tanousac106bf2023-06-07 09:24:59 -07004098 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004099 return;
4100 }
4101
4102 if (bootIndex == 0 || codeIndex == 0)
4103 {
4104 // 0 is an invalid index
Ed Tanousac106bf2023-06-07 09:24:59 -07004105 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004106 return;
4107 }
4108
ZhikuiRena3316fc2020-01-29 14:58:08 -08004109 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004110 [asyncResp, entryId, bootIndex,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004111 codeIndex](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304112 const boost::container::flat_map<
4113 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4114 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004115 if (ec)
4116 {
Ed Tanous62598e32023-07-17 17:06:25 -07004117 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004118 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004119 return;
4120 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004121
Ed Tanous002d39b2022-05-31 08:59:27 -07004122 if (postcode.empty())
4123 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004124 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07004125 return;
4126 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004127
Ed Tanousac106bf2023-06-07 09:24:59 -07004128 if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004129 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004130 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004131 return;
4132 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004133 },
Jonathan Doman15124762021-01-07 17:54:17 -08004134 "xyz.openbmc_project.State.Boot.PostCode0",
4135 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004136 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4137 bootIndex);
4138}
4139
Ed Tanousac106bf2023-06-07 09:24:59 -07004140static void
4141 getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4142 const uint16_t bootIndex, const uint16_t bootCount,
4143 const uint64_t entryCount, size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004144{
4145 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004146 [asyncResp, bootIndex, bootCount, entryCount, skip,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004147 top](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304148 const boost::container::flat_map<
4149 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4150 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004151 if (ec)
4152 {
Ed Tanous62598e32023-07-17 17:06:25 -07004153 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004154 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004155 return;
4156 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004157
Ed Tanous002d39b2022-05-31 08:59:27 -07004158 uint64_t endCount = entryCount;
4159 if (!postcode.empty())
4160 {
4161 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07004162 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004163 {
Patrick Williams89492a12023-05-10 07:51:34 -05004164 uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip),
4165 entryCount) -
4166 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004167 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07004168 std::min(static_cast<uint64_t>(top + skip), endCount) -
4169 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004170
Ed Tanousac106bf2023-06-07 09:24:59 -07004171 fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4172 thisBootSkip, thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004173 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004174 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004175 }
4176
4177 // continue to previous bootIndex
4178 if (bootIndex < bootCount)
4179 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004180 getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1),
Ed Tanous002d39b2022-05-31 08:59:27 -07004181 bootCount, endCount, skip, top);
4182 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08004183 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07004184 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004185 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous002d39b2022-05-31 08:59:27 -07004186 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
4187 std::to_string(skip + top);
4188 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004189 },
Jonathan Doman15124762021-01-07 17:54:17 -08004190 "xyz.openbmc_project.State.Boot.PostCode0",
4191 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004192 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4193 bootIndex);
4194}
4195
zhanghch058d1b46d2021-04-01 11:18:24 +08004196static void
Ed Tanousac106bf2023-06-07 09:24:59 -07004197 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07004198 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004199{
4200 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07004201 sdbusplus::asio::getProperty<uint16_t>(
4202 *crow::connections::systemBus,
4203 "xyz.openbmc_project.State.Boot.PostCode0",
4204 "/xyz/openbmc_project/State/Boot/PostCode0",
4205 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
Ed Tanousac106bf2023-06-07 09:24:59 -07004206 [asyncResp, entryCount, skip, top](const boost::system::error_code& ec,
4207 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004208 if (ec)
4209 {
Ed Tanous62598e32023-07-17 17:06:25 -07004210 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanousac106bf2023-06-07 09:24:59 -07004211 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004212 return;
4213 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004214 getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004215 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08004216}
4217
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004218inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004219{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004220 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004221 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07004222 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004223 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004224 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004225 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4226 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004227 query_param::QueryCapabilities capabilities = {
4228 .canDelegateTop = true,
4229 .canDelegateSkip = true,
4230 };
4231 query_param::Query delegatedQuery;
4232 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00004233 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07004234 {
4235 return;
4236 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004237 if constexpr (bmcwebEnableMultiHost)
4238 {
4239 // Option currently returns no systems. TBD
4240 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4241 systemName);
4242 return;
4243 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004244
4245 if (systemName != "system")
4246 {
4247 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4248 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004249 return;
4250 }
Ed Tanous002d39b2022-05-31 08:59:27 -07004251 asyncResp->res.jsonValue["@odata.type"] =
4252 "#LogEntryCollection.LogEntryCollection";
4253 asyncResp->res.jsonValue["@odata.id"] =
4254 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
4255 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4256 asyncResp->res.jsonValue["Description"] =
4257 "Collection of POST Code Log Entries";
4258 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4259 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07004260 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08004261 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07004262 getCurrentBootNumber(asyncResp, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004263 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004264}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004265
George Liu647b3cd2021-07-05 12:43:56 +08004266inline void requestRoutesPostCodesEntryAdditionalData(App& app)
4267{
George Liu0fda0f12021-11-16 10:06:17 +08004268 BMCWEB_ROUTE(
4269 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004270 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08004271 .privileges(redfish::privileges::getLogEntry)
4272 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004273 [&app](const crow::Request& req,
4274 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004275 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07004276 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004277 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004278 {
4279 return;
4280 }
Matt Spinler72e21372023-04-19 12:53:33 -05004281 if (!http_helpers::isContentTypeAllowed(
Ed Tanous99351cd2022-08-07 16:42:51 -07004282 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07004283 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07004284 {
4285 asyncResp->res.result(boost::beast::http::status::bad_request);
4286 return;
4287 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004288 if constexpr (bmcwebEnableMultiHost)
4289 {
4290 // Option currently returns no systems. TBD
4291 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4292 systemName);
4293 return;
4294 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004295 if (systemName != "system")
4296 {
4297 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4298 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004299 return;
4300 }
George Liu647b3cd2021-07-05 12:43:56 +08004301
Ed Tanous002d39b2022-05-31 08:59:27 -07004302 uint64_t currentValue = 0;
4303 uint16_t index = 0;
4304 if (!parsePostCode(postCodeID, currentValue, index))
4305 {
4306 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
4307 return;
4308 }
George Liu647b3cd2021-07-05 12:43:56 +08004309
Ed Tanous002d39b2022-05-31 08:59:27 -07004310 crow::connections::systemBus->async_method_call(
4311 [asyncResp, postCodeID, currentValue](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004312 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07004313 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
4314 postcodes) {
4315 if (ec.value() == EBADR)
4316 {
4317 messages::resourceNotFound(asyncResp->res, "LogEntry",
4318 postCodeID);
4319 return;
4320 }
4321 if (ec)
4322 {
Ed Tanous62598e32023-07-17 17:06:25 -07004323 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004324 messages::internalError(asyncResp->res);
4325 return;
4326 }
George Liu647b3cd2021-07-05 12:43:56 +08004327
Ed Tanous002d39b2022-05-31 08:59:27 -07004328 size_t value = static_cast<size_t>(currentValue) - 1;
4329 if (value == std::string::npos || postcodes.size() < currentValue)
4330 {
Ed Tanous62598e32023-07-17 17:06:25 -07004331 BMCWEB_LOG_WARNING("Wrong currentValue value");
Ed Tanous002d39b2022-05-31 08:59:27 -07004332 messages::resourceNotFound(asyncResp->res, "LogEntry",
4333 postCodeID);
4334 return;
4335 }
George Liu647b3cd2021-07-05 12:43:56 +08004336
Ed Tanous002d39b2022-05-31 08:59:27 -07004337 const auto& [tID, c] = postcodes[value];
4338 if (c.empty())
4339 {
Ed Tanous62598e32023-07-17 17:06:25 -07004340 BMCWEB_LOG_WARNING("No found post code data");
Ed Tanous002d39b2022-05-31 08:59:27 -07004341 messages::resourceNotFound(asyncResp->res, "LogEntry",
4342 postCodeID);
4343 return;
4344 }
4345 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4346 const char* d = reinterpret_cast<const char*>(c.data());
4347 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004348
Ed Tanousd9f6c622022-03-17 09:12:17 -07004349 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004350 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004351 asyncResp->res.addHeader(
4352 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous27b0cf92023-08-07 12:02:40 -07004353 asyncResp->res.write(crow::utility::base64encode(strData));
Patrick Williams5a39f772023-10-20 11:20:21 -05004354 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004355 "xyz.openbmc_project.State.Boot.PostCode0",
4356 "/xyz/openbmc_project/State/Boot/PostCode0",
4357 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
Patrick Williams5a39f772023-10-20 11:20:21 -05004358 });
George Liu647b3cd2021-07-05 12:43:56 +08004359}
4360
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004361inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004362{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004363 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004364 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004365 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004366 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004367 [&app](const crow::Request& req,
4368 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004369 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004370 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004371 {
4372 return;
4373 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004374 if constexpr (bmcwebEnableMultiHost)
4375 {
4376 // Option currently returns no systems. TBD
4377 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4378 systemName);
4379 return;
4380 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004381 if (systemName != "system")
4382 {
4383 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4384 systemName);
4385 return;
4386 }
4387
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004388 getPostCodeForEntry(asyncResp, targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05004389 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004390}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004391
Ed Tanous1da66f72018-07-27 16:13:37 -07004392} // namespace redfish