blob: 6ea165d799737e6e338049f687da2699747aec2c [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(
963 [asyncResp, payload, createdObjPath,
964 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
2201inline void fillHostLoggerEntryJson(const std::string& logEntryID,
2202 const std::string& 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 Tanous002d39b2022-05-31 08:59:27 -07002371 const std::string& 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
Patrick Williams84396af2023-05-11 11:47:45 -05002375 auto [ptr, ec] = std::from_chars(&*targetID.begin(), &*targetID.end(),
2376 idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002377 if (ec == std::errc::invalid_argument ||
2378 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002379 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002380 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002381 return;
2382 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002383
Ed Tanous002d39b2022-05-31 08:59:27 -07002384 std::vector<std::filesystem::path> hostLoggerFiles;
2385 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2386 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002387 BMCWEB_LOG_DEBUG("Failed to get host log file path");
Ed Tanous002d39b2022-05-31 08:59:27 -07002388 return;
2389 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002390
Ed Tanous002d39b2022-05-31 08:59:27 -07002391 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002392 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002393 std::vector<std::string> logEntries;
2394 // We can get specific entry by skip and top. For example, if we
2395 // want to get nth entry, we can set skip = n-1 and top = 1 to
2396 // get that entry
2397 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2398 logCount))
2399 {
2400 messages::internalError(asyncResp->res);
2401 return;
2402 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002403
Ed Tanous002d39b2022-05-31 08:59:27 -07002404 if (!logEntries.empty())
2405 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002406 nlohmann::json::object_t hostLogEntry;
2407 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2408 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002409 return;
2410 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002411
Ed Tanous002d39b2022-05-31 08:59:27 -07002412 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002413 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Patrick Williams5a39f772023-10-20 11:20:21 -05002414 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002415}
2416
Claire Weinandd72e872022-08-15 14:20:06 -07002417inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002418 crow::App& app, const crow::Request& req,
2419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2420{
2421 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2422 {
2423 return;
2424 }
2425 // Collections don't include the static data added by SubRoute
2426 // because it has a duplicate entry for members
2427 asyncResp->res.jsonValue["@odata.type"] =
2428 "#LogServiceCollection.LogServiceCollection";
2429 asyncResp->res.jsonValue["@odata.id"] =
2430 "/redfish/v1/Managers/bmc/LogServices";
2431 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2432 asyncResp->res.jsonValue["Description"] =
2433 "Collection of LogServices for this Manager";
2434 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2435 logServiceArray = nlohmann::json::array();
2436
2437#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002438 nlohmann::json::object_t journal;
2439 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002440 logServiceArray.emplace_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002441#endif
2442
2443 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2444
2445#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
George Liu15912152023-01-11 10:18:18 +08002446 constexpr std::array<std::string_view, 1> interfaces = {
George Liu7a1dbc42022-12-07 16:03:22 +08002447 "xyz.openbmc_project.Collection.DeleteAll"};
2448 dbus::utility::getSubTreePaths(
2449 "/xyz/openbmc_project/dump", 0, interfaces,
Claire Weinanfdd26902022-03-01 14:18:25 -08002450 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08002451 const boost::system::error_code& ec,
Claire Weinanfdd26902022-03-01 14:18:25 -08002452 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2453 if (ec)
2454 {
Ed Tanous62598e32023-07-17 17:06:25 -07002455 BMCWEB_LOG_ERROR(
2456 "handleBMCLogServicesCollectionGet respHandler got error {}",
2457 ec);
Claire Weinanfdd26902022-03-01 14:18:25 -08002458 // Assume that getting an error simply means there are no dump
2459 // LogServices. Return without adding any error response.
2460 return;
2461 }
2462
2463 nlohmann::json& logServiceArrayLocal =
2464 asyncResp->res.jsonValue["Members"];
2465
2466 for (const std::string& path : subTreePaths)
2467 {
2468 if (path == "/xyz/openbmc_project/dump/bmc")
2469 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002470 nlohmann::json::object_t member;
2471 member["@odata.id"] =
2472 "/redfish/v1/Managers/bmc/LogServices/Dump";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002473 logServiceArrayLocal.emplace_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002474 }
2475 else if (path == "/xyz/openbmc_project/dump/faultlog")
2476 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002477 nlohmann::json::object_t member;
2478 member["@odata.id"] =
2479 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002480 logServiceArrayLocal.emplace_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002481 }
2482 }
2483
2484 asyncResp->res.jsonValue["Members@odata.count"] =
2485 logServiceArrayLocal.size();
Patrick Williams5a39f772023-10-20 11:20:21 -05002486 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002487#endif
2488}
2489
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002490inline void requestRoutesBMCLogServiceCollection(App& app)
2491{
2492 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002493 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002494 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002495 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002496}
Ed Tanous1da66f72018-07-27 16:13:37 -07002497
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002498inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002499{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002500 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002501 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002502 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002503 [&app](const crow::Request& req,
2504 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002505 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002506 {
2507 return;
2508 }
2509 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05002510 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 asyncResp->res.jsonValue["@odata.id"] =
2512 "/redfish/v1/Managers/bmc/LogServices/Journal";
2513 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2514 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08002515 asyncResp->res.jsonValue["Id"] = "Journal";
Ed Tanous002d39b2022-05-31 08:59:27 -07002516 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302517
Ed Tanous002d39b2022-05-31 08:59:27 -07002518 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002519 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002520 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2521 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2522 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302523
Ed Tanous002d39b2022-05-31 08:59:27 -07002524 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2525 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Patrick Williams5a39f772023-10-20 11:20:21 -05002526 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002527}
Jason M. Billse1f26342018-07-18 12:12:00 -07002528
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002529static int
2530 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2531 sd_journal* journal,
2532 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002533{
2534 // Get the Log Entry contents
2535 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002536
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002537 std::string message;
2538 std::string_view syslogID;
2539 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2540 if (ret < 0)
2541 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002542 BMCWEB_LOG_DEBUG("Failed to read SYSLOG_IDENTIFIER field: {}",
Ed Tanous62598e32023-07-17 17:06:25 -07002543 strerror(-ret));
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002544 }
2545 if (!syslogID.empty())
2546 {
2547 message += std::string(syslogID) + ": ";
2548 }
2549
Ed Tanous39e77502019-03-04 17:35:53 -08002550 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002551 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002552 if (ret < 0)
2553 {
Ed Tanous62598e32023-07-17 17:06:25 -07002554 BMCWEB_LOG_ERROR("Failed to read MESSAGE field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002555 return 1;
2556 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002557 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002558
2559 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002560 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002561 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002562 if (ret < 0)
2563 {
Carson Labradobf2dded2023-08-10 00:37:06 +00002564 BMCWEB_LOG_DEBUG("Failed to read PRIORITY field: {}", strerror(-ret));
Jason M. Billse1f26342018-07-18 12:12:00 -07002565 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002566
2567 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002568 std::string entryTimeStr;
2569 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002570 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002571 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002572 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002573
2574 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002575 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07002576 bmcJournalLogEntryJson["@odata.id"] = boost::urls::format(
2577 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/{}",
Willy Tueddfc432022-09-26 16:46:38 +00002578 bmcJournalLogEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07002579 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2580 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2581 bmcJournalLogEntryJson["Message"] = std::move(message);
2582 bmcJournalLogEntryJson["EntryType"] = "Oem";
Ed Tanousddf35642024-03-27 14:12:21 -07002583 log_entry::EventSeverity severityEnum = log_entry::EventSeverity::OK;
2584 if (severity <= 2)
2585 {
2586 severityEnum = log_entry::EventSeverity::Critical;
2587 }
2588 else if (severity <= 4)
2589 {
2590 severityEnum = log_entry::EventSeverity::Warning;
2591 }
2592
2593 bmcJournalLogEntryJson["Severity"] = severityEnum;
Jason M. Bills84afc482022-06-24 12:38:23 -07002594 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2595 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002596 return 0;
2597}
2598
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002599inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002600{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002601 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002602 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002603 .methods(boost::beast::http::verb::get)(
2604 [&app](const crow::Request& req,
2605 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2606 query_param::QueryCapabilities capabilities = {
2607 .canDelegateTop = true,
2608 .canDelegateSkip = true,
2609 };
2610 query_param::Query delegatedQuery;
2611 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002612 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002613 {
2614 return;
2615 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002616
2617 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002618 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002619
Ed Tanous002d39b2022-05-31 08:59:27 -07002620 // Collections don't include the static data added by SubRoute
2621 // because it has a duplicate entry for members
2622 asyncResp->res.jsonValue["@odata.type"] =
2623 "#LogEntryCollection.LogEntryCollection";
2624 asyncResp->res.jsonValue["@odata.id"] =
2625 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2626 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2627 asyncResp->res.jsonValue["Description"] =
2628 "Collection of BMC Journal Entries";
2629 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2630 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002631
Ed Tanous002d39b2022-05-31 08:59:27 -07002632 // Go through the journal and use the timestamp to create a
2633 // unique ID for each entry
2634 sd_journal* journalTmp = nullptr;
2635 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2636 if (ret < 0)
2637 {
Ed Tanous62598e32023-07-17 17:06:25 -07002638 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002639 messages::internalError(asyncResp->res);
2640 return;
2641 }
2642 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2643 journalTmp, sd_journal_close);
2644 journalTmp = nullptr;
2645 uint64_t entryCount = 0;
2646 // Reset the unique ID on the first entry
2647 bool firstEntry = true;
2648 SD_JOURNAL_FOREACH(journal.get())
2649 {
2650 entryCount++;
2651 // Handle paging using skip (number of entries to skip from
2652 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002653 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002654 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002655 continue;
2656 }
2657
2658 std::string idStr;
2659 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2660 {
2661 continue;
2662 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002663 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002664
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002665 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002666 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2667 bmcJournalLogEntry) != 0)
2668 {
George Liu0fda0f12021-11-16 10:06:17 +08002669 messages::internalError(asyncResp->res);
2670 return;
2671 }
Patrick Williamsb2ba3072023-05-12 10:27:39 -05002672 logEntryArray.emplace_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002673 }
2674 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002675 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002676 {
2677 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2678 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002679 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002680 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002681 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002682}
Jason M. Billse1f26342018-07-18 12:12:00 -07002683
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002684inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002685{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002686 BMCWEB_ROUTE(app,
2687 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002688 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002689 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002690 [&app](const crow::Request& req,
2691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2692 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002693 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002694 {
2695 return;
2696 }
2697 // Convert the unique ID back to a timestamp to find the entry
Myung Bae75e8e212023-11-30 12:53:46 -08002698 sd_id128_t bootID{};
Ed Tanous002d39b2022-05-31 08:59:27 -07002699 uint64_t ts = 0;
2700 uint64_t index = 0;
Myung Bae75e8e212023-11-30 12:53:46 -08002701 if (!getTimestampFromID(asyncResp, entryID, bootID, ts, index))
Ed Tanous002d39b2022-05-31 08:59:27 -07002702 {
2703 return;
2704 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002705
Ed Tanous002d39b2022-05-31 08:59:27 -07002706 sd_journal* journalTmp = nullptr;
2707 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2708 if (ret < 0)
2709 {
Ed Tanous62598e32023-07-17 17:06:25 -07002710 BMCWEB_LOG_ERROR("failed to open journal: {}", strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002711 messages::internalError(asyncResp->res);
2712 return;
2713 }
2714 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2715 journalTmp, sd_journal_close);
2716 journalTmp = nullptr;
2717 // Go to the timestamp in the log and move to the entry at the
2718 // index tracking the unique ID
2719 std::string idStr;
2720 bool firstEntry = true;
Myung Bae75e8e212023-11-30 12:53:46 -08002721 ret = sd_journal_seek_monotonic_usec(journal.get(), bootID, ts);
Ed Tanous002d39b2022-05-31 08:59:27 -07002722 if (ret < 0)
2723 {
Ed Tanous62598e32023-07-17 17:06:25 -07002724 BMCWEB_LOG_ERROR("failed to seek to an entry in journal{}",
2725 strerror(-ret));
Ed Tanous002d39b2022-05-31 08:59:27 -07002726 messages::internalError(asyncResp->res);
2727 return;
2728 }
2729 for (uint64_t i = 0; i <= index; i++)
2730 {
2731 sd_journal_next(journal.get());
2732 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2733 {
2734 messages::internalError(asyncResp->res);
2735 return;
2736 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002737 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002738 }
2739 // Confirm that the entry ID matches what was requested
2740 if (idStr != entryID)
2741 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002742 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002743 return;
2744 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002745
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002746 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002747 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002748 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002749 {
2750 messages::internalError(asyncResp->res);
2751 return;
2752 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002753 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Patrick Williams5a39f772023-10-20 11:20:21 -05002754 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002755}
2756
Claire Weinanfdd26902022-03-01 14:18:25 -08002757inline void
2758 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2759 const std::string& dumpType)
2760{
2761 std::string dumpPath;
2762 std::string overWritePolicy;
2763 bool collectDiagnosticDataSupported = false;
2764
2765 if (dumpType == "BMC")
2766 {
2767 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2768 overWritePolicy = "WrapsWhenFull";
2769 collectDiagnosticDataSupported = true;
2770 }
2771 else if (dumpType == "FaultLog")
2772 {
2773 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2774 overWritePolicy = "Unknown";
2775 collectDiagnosticDataSupported = false;
2776 }
2777 else if (dumpType == "System")
2778 {
2779 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2780 overWritePolicy = "WrapsWhenFull";
2781 collectDiagnosticDataSupported = true;
2782 }
2783 else
2784 {
Ed Tanous62598e32023-07-17 17:06:25 -07002785 BMCWEB_LOG_ERROR("getDumpServiceInfo() invalid dump type: {}",
2786 dumpType);
Claire Weinanfdd26902022-03-01 14:18:25 -08002787 messages::internalError(asyncResp->res);
2788 return;
2789 }
2790
2791 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2792 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2793 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2794 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2795 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2796 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2797
2798 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002799 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002800 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2801 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2802 redfishDateTimeOffset.second;
2803
2804 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
Claire Weinanfdd26902022-03-01 14:18:25 -08002805
2806 if (collectDiagnosticDataSupported)
2807 {
2808 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2809 ["target"] =
2810 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2811 }
Claire Weinan0d946212022-07-13 19:40:19 -07002812
2813 constexpr std::array<std::string_view, 1> interfaces = {deleteAllInterface};
2814 dbus::utility::getSubTreePaths(
2815 "/xyz/openbmc_project/dump", 0, interfaces,
2816 [asyncResp, dumpType, dumpPath](
2817 const boost::system::error_code& ec,
2818 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2819 if (ec)
2820 {
Ed Tanous62598e32023-07-17 17:06:25 -07002821 BMCWEB_LOG_ERROR("getDumpServiceInfo respHandler got error {}", ec);
Claire Weinan0d946212022-07-13 19:40:19 -07002822 // Assume that getting an error simply means there are no dump
2823 // LogServices. Return without adding any error response.
2824 return;
2825 }
Ed Tanous18f8f602023-07-18 10:07:23 -07002826 std::string dbusDumpPath = getDumpPath(dumpType);
Claire Weinan0d946212022-07-13 19:40:19 -07002827 for (const std::string& path : subTreePaths)
2828 {
2829 if (path == dbusDumpPath)
2830 {
2831 asyncResp->res
2832 .jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2833 dumpPath + "/Actions/LogService.ClearLog";
2834 break;
2835 }
2836 }
Patrick Williams5a39f772023-10-20 11:20:21 -05002837 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002838}
2839
2840inline void handleLogServicesDumpServiceGet(
2841 crow::App& app, const std::string& dumpType, const crow::Request& req,
2842 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2843{
2844 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2845 {
2846 return;
2847 }
2848 getDumpServiceInfo(asyncResp, dumpType);
2849}
2850
Ed Tanous22d268c2022-05-19 09:39:07 -07002851inline void handleLogServicesDumpServiceComputerSystemGet(
2852 crow::App& app, const crow::Request& req,
2853 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2854 const std::string& chassisId)
2855{
2856 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2857 {
2858 return;
2859 }
2860 if (chassisId != "system")
2861 {
2862 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2863 return;
2864 }
2865 getDumpServiceInfo(asyncResp, "System");
2866}
2867
Claire Weinanfdd26902022-03-01 14:18:25 -08002868inline void handleLogServicesDumpEntriesCollectionGet(
2869 crow::App& app, const std::string& dumpType, const crow::Request& req,
2870 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2871{
2872 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2873 {
2874 return;
2875 }
2876 getDumpEntryCollection(asyncResp, dumpType);
2877}
2878
Ed Tanous22d268c2022-05-19 09:39:07 -07002879inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2880 crow::App& app, const crow::Request& req,
2881 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2882 const std::string& chassisId)
2883{
2884 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2885 {
2886 return;
2887 }
2888 if (chassisId != "system")
2889 {
2890 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2891 return;
2892 }
2893 getDumpEntryCollection(asyncResp, "System");
2894}
2895
Claire Weinanfdd26902022-03-01 14:18:25 -08002896inline void handleLogServicesDumpEntryGet(
2897 crow::App& app, const std::string& dumpType, const crow::Request& req,
2898 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2899 const std::string& dumpId)
2900{
2901 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2902 {
2903 return;
2904 }
2905 getDumpEntryById(asyncResp, dumpId, dumpType);
2906}
Carson Labrado168d1b12023-03-27 17:04:46 +00002907
Ed Tanous22d268c2022-05-19 09:39:07 -07002908inline void handleLogServicesDumpEntryComputerSystemGet(
2909 crow::App& app, const crow::Request& req,
2910 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2911 const std::string& chassisId, const std::string& dumpId)
2912{
2913 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2914 {
2915 return;
2916 }
2917 if (chassisId != "system")
2918 {
2919 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2920 return;
2921 }
2922 getDumpEntryById(asyncResp, dumpId, "System");
2923}
Claire Weinanfdd26902022-03-01 14:18:25 -08002924
2925inline void handleLogServicesDumpEntryDelete(
2926 crow::App& app, const std::string& dumpType, const crow::Request& req,
2927 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2928 const std::string& dumpId)
2929{
2930 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2931 {
2932 return;
2933 }
2934 deleteDumpEntry(asyncResp, dumpId, dumpType);
2935}
2936
Ed Tanous22d268c2022-05-19 09:39:07 -07002937inline void handleLogServicesDumpEntryComputerSystemDelete(
2938 crow::App& app, const crow::Request& req,
2939 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2940 const std::string& chassisId, const std::string& dumpId)
2941{
2942 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2943 {
2944 return;
2945 }
2946 if (chassisId != "system")
2947 {
2948 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2949 return;
2950 }
2951 deleteDumpEntry(asyncResp, dumpId, "System");
2952}
2953
Carson Labrado168d1b12023-03-27 17:04:46 +00002954inline void handleLogServicesDumpEntryDownloadGet(
2955 crow::App& app, const std::string& dumpType, const crow::Request& req,
2956 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2957 const std::string& dumpId)
2958{
2959 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2960 {
2961 return;
2962 }
2963 downloadDumpEntry(asyncResp, dumpId, dumpType);
2964}
2965
2966inline void handleDBusEventLogEntryDownloadGet(
2967 crow::App& app, const std::string& dumpType, const crow::Request& req,
2968 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2969 const std::string& systemName, const std::string& entryID)
2970{
2971 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2972 {
2973 return;
2974 }
2975 if (!http_helpers::isContentTypeAllowed(
2976 req.getHeaderValue("Accept"),
2977 http_helpers::ContentType::OctetStream, true))
2978 {
2979 asyncResp->res.result(boost::beast::http::status::bad_request);
2980 return;
2981 }
2982 downloadEventLogEntry(asyncResp, systemName, entryID, dumpType);
2983}
2984
Claire Weinanfdd26902022-03-01 14:18:25 -08002985inline void handleLogServicesDumpCollectDiagnosticDataPost(
2986 crow::App& app, const std::string& dumpType, const crow::Request& req,
2987 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2988{
2989 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2990 {
2991 return;
2992 }
2993 createDump(asyncResp, req, dumpType);
2994}
2995
Ed Tanous22d268c2022-05-19 09:39:07 -07002996inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2997 crow::App& app, const crow::Request& req,
2998 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08002999 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003000{
3001 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3002 {
3003 return;
3004 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003005
3006 if constexpr (bmcwebEnableMultiHost)
Ed Tanous22d268c2022-05-19 09:39:07 -07003007 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003008 // Option currently returns no systems. TBD
3009 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3010 systemName);
3011 return;
3012 }
3013 if (systemName != "system")
3014 {
3015 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3016 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003017 return;
3018 }
3019 createDump(asyncResp, req, "System");
3020}
3021
Claire Weinanfdd26902022-03-01 14:18:25 -08003022inline void handleLogServicesDumpClearLogPost(
3023 crow::App& app, const std::string& dumpType, const crow::Request& req,
3024 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3025{
3026 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3027 {
3028 return;
3029 }
3030 clearDump(asyncResp, dumpType);
3031}
3032
Ed Tanous22d268c2022-05-19 09:39:07 -07003033inline void handleLogServicesDumpClearLogComputerSystemPost(
3034 crow::App& app, const crow::Request& req,
3035 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003036 const std::string& systemName)
Ed Tanous22d268c2022-05-19 09:39:07 -07003037{
3038 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3039 {
3040 return;
3041 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003042 if constexpr (bmcwebEnableMultiHost)
Ed Tanous22d268c2022-05-19 09:39:07 -07003043 {
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003044 // Option currently returns no systems. TBD
3045 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3046 systemName);
3047 return;
3048 }
3049 if (systemName != "system")
3050 {
3051 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3052 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003053 return;
3054 }
3055 clearDump(asyncResp, "System");
3056}
3057
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003058inline void requestRoutesBMCDumpService(App& app)
3059{
3060 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003061 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003062 .methods(boost::beast::http::verb::get)(std::bind_front(
3063 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003064}
3065
3066inline void requestRoutesBMCDumpEntryCollection(App& app)
3067{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003068 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003069 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08003070 .methods(boost::beast::http::verb::get)(std::bind_front(
3071 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003072}
3073
3074inline void requestRoutesBMCDumpEntry(App& app)
3075{
3076 BMCWEB_ROUTE(app,
3077 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003078 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003079 .methods(boost::beast::http::verb::get)(std::bind_front(
3080 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
3081
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003082 BMCWEB_ROUTE(app,
3083 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003084 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08003085 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3086 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003087}
3088
Carson Labrado168d1b12023-03-27 17:04:46 +00003089inline void requestRoutesBMCDumpEntryDownload(App& app)
3090{
3091 BMCWEB_ROUTE(
3092 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003093 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003094 .privileges(redfish::privileges::getLogEntry)
3095 .methods(boost::beast::http::verb::get)(std::bind_front(
3096 handleLogServicesDumpEntryDownloadGet, std::ref(app), "BMC"));
3097}
3098
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003099inline void requestRoutesBMCDumpCreate(App& app)
3100{
George Liu0fda0f12021-11-16 10:06:17 +08003101 BMCWEB_ROUTE(
3102 app,
3103 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003104 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003105 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08003106 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
3107 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003108}
3109
3110inline void requestRoutesBMCDumpClear(App& app)
3111{
George Liu0fda0f12021-11-16 10:06:17 +08003112 BMCWEB_ROUTE(
3113 app,
3114 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003115 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08003116 .methods(boost::beast::http::verb::post)(std::bind_front(
3117 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
3118}
3119
Carson Labrado168d1b12023-03-27 17:04:46 +00003120inline void requestRoutesDBusEventLogEntryDownload(App& app)
3121{
3122 BMCWEB_ROUTE(
3123 app,
Ravi Teja9e9d99d2023-11-08 05:33:59 -06003124 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment/")
Carson Labrado168d1b12023-03-27 17:04:46 +00003125 .privileges(redfish::privileges::getLogEntry)
3126 .methods(boost::beast::http::verb::get)(std::bind_front(
3127 handleDBusEventLogEntryDownloadGet, std::ref(app), "System"));
3128}
3129
Claire Weinanfdd26902022-03-01 14:18:25 -08003130inline void requestRoutesFaultLogDumpService(App& app)
3131{
3132 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
3133 .privileges(redfish::privileges::getLogService)
3134 .methods(boost::beast::http::verb::get)(std::bind_front(
3135 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
3136}
3137
3138inline void requestRoutesFaultLogDumpEntryCollection(App& app)
3139{
3140 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
3141 .privileges(redfish::privileges::getLogEntryCollection)
3142 .methods(boost::beast::http::verb::get)(
3143 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
3144 std::ref(app), "FaultLog"));
3145}
3146
3147inline void requestRoutesFaultLogDumpEntry(App& app)
3148{
3149 BMCWEB_ROUTE(app,
3150 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3151 .privileges(redfish::privileges::getLogEntry)
3152 .methods(boost::beast::http::verb::get)(std::bind_front(
3153 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
3154
3155 BMCWEB_ROUTE(app,
3156 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
3157 .privileges(redfish::privileges::deleteLogEntry)
3158 .methods(boost::beast::http::verb::delete_)(std::bind_front(
3159 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
3160}
3161
3162inline void requestRoutesFaultLogDumpClear(App& app)
3163{
3164 BMCWEB_ROUTE(
3165 app,
3166 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
3167 .privileges(redfish::privileges::postLogService)
3168 .methods(boost::beast::http::verb::post)(std::bind_front(
3169 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003170}
3171
3172inline void requestRoutesSystemDumpService(App& app)
3173{
Ed Tanous22d268c2022-05-19 09:39:07 -07003174 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07003175 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003176 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003177 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003178}
3179
3180inline void requestRoutesSystemDumpEntryCollection(App& app)
3181{
Ed Tanous22d268c2022-05-19 09:39:07 -07003182 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003183 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07003184 .methods(boost::beast::http::verb::get)(std::bind_front(
3185 handleLogServicesDumpEntriesCollectionComputerSystemGet,
3186 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003187}
3188
3189inline void requestRoutesSystemDumpEntry(App& app)
3190{
3191 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003192 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003193 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003194 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003195 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003196
3197 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003198 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003199 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003200 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003201 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003202}
3203
3204inline void requestRoutesSystemDumpCreate(App& app)
3205{
George Liu0fda0f12021-11-16 10:06:17 +08003206 BMCWEB_ROUTE(
3207 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003208 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003209 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07003210 .methods(boost::beast::http::verb::post)(std::bind_front(
3211 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
3212 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003213}
3214
3215inline void requestRoutesSystemDumpClear(App& app)
3216{
George Liu0fda0f12021-11-16 10:06:17 +08003217 BMCWEB_ROUTE(
3218 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003219 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003220 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07003221 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07003222 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003223}
3224
3225inline void requestRoutesCrashdumpService(App& app)
3226{
3227 // Note: Deviated from redfish privilege registry for GET & HEAD
3228 // method for security reasons.
3229 /**
3230 * Functions triggers appropriate requests on DBus
3231 */
Ed Tanous22d268c2022-05-19 09:39:07 -07003232 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07003233 // This is incorrect, should be:
3234 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003235 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003236 .methods(boost::beast::http::verb::get)(
3237 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003238 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3239 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003240 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003241 {
3242 return;
3243 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003244 if constexpr (bmcwebEnableMultiHost)
3245 {
3246 // Option currently returns no systems. TBD
3247 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3248 systemName);
3249 return;
3250 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003251 if (systemName != "system")
3252 {
3253 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3254 systemName);
3255 return;
3256 }
3257
Ed Tanous002d39b2022-05-31 08:59:27 -07003258 // Copy over the static data to include the entries added by
3259 // SubRoute
3260 asyncResp->res.jsonValue["@odata.id"] =
3261 "/redfish/v1/Systems/system/LogServices/Crashdump";
3262 asyncResp->res.jsonValue["@odata.type"] =
3263 "#LogService.v1_2_0.LogService";
3264 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3265 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
V-Sanjana15b89722023-05-11 16:27:03 +05303266 asyncResp->res.jsonValue["Id"] = "Crashdump";
Ed Tanous002d39b2022-05-31 08:59:27 -07003267 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3268 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303269
Ed Tanous002d39b2022-05-31 08:59:27 -07003270 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003271 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003272 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3273 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3274 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303275
Ed Tanous002d39b2022-05-31 08:59:27 -07003276 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -07003277 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Ed Tanous002d39b2022-05-31 08:59:27 -07003278 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
3279 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
3280 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
3281 ["target"] =
3282 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
Patrick Williams5a39f772023-10-20 11:20:21 -05003283 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003284}
3285
3286void inline requestRoutesCrashdumpClear(App& app)
3287{
George Liu0fda0f12021-11-16 10:06:17 +08003288 BMCWEB_ROUTE(
3289 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003290 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003291 // This is incorrect, should be:
3292 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003293 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003294 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003295 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003296 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3297 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003298 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003299 {
3300 return;
3301 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003302 if constexpr (bmcwebEnableMultiHost)
3303 {
3304 // Option currently returns no systems. TBD
3305 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3306 systemName);
3307 return;
3308 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003309 if (systemName != "system")
3310 {
3311 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3312 systemName);
3313 return;
3314 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003315 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003316 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003317 const std::string&) {
3318 if (ec)
3319 {
3320 messages::internalError(asyncResp->res);
3321 return;
3322 }
3323 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003324 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003325 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003326 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003327}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003328
zhanghch058d1b46d2021-04-01 11:18:24 +08003329static void
3330 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3331 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003332{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003333 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003334 [asyncResp, logID,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003335 &logEntryJson](const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -08003336 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003337 if (ec)
3338 {
Ed Tanous62598e32023-07-17 17:06:25 -07003339 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003340 if (ec.value() ==
3341 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003342 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003343 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003344 }
3345 else
3346 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003347 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003348 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003349 return;
3350 }
3351
3352 std::string timestamp{};
3353 std::string filename{};
3354 std::string logfile{};
3355 parseCrashdumpParameters(params, filename, timestamp, logfile);
3356
3357 if (filename.empty() || timestamp.empty())
3358 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003359 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003360 return;
3361 }
3362
3363 std::string crashdumpURI =
3364 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3365 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003366 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003367 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07003368 logEntry["@odata.id"] = boost::urls::format(
3369 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/{}",
3370 logID);
Jason M. Bills84afc482022-06-24 12:38:23 -07003371 logEntry["Name"] = "CPU Crashdump";
3372 logEntry["Id"] = logID;
3373 logEntry["EntryType"] = "Oem";
3374 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3375 logEntry["DiagnosticDataType"] = "OEM";
3376 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3377 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003378
3379 // If logEntryJson references an array of LogEntry resources
3380 // ('Members' list), then push this as a new entry, otherwise set it
3381 // directly
3382 if (logEntryJson.is_array())
3383 {
3384 logEntryJson.push_back(logEntry);
3385 asyncResp->res.jsonValue["Members@odata.count"] =
3386 logEntryJson.size();
3387 }
3388 else
3389 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003390 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003391 }
3392 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003393 sdbusplus::asio::getAllProperties(
3394 *crow::connections::systemBus, crashdumpObject,
3395 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3396 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003397}
3398
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003399inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003400{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003401 // Note: Deviated from redfish privilege registry for GET & HEAD
3402 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003403 /**
3404 * Functions triggers appropriate requests on DBus
3405 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003406 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003407 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003408 // This is incorrect, should be.
3409 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003410 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003411 .methods(boost::beast::http::verb::get)(
3412 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003413 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3414 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003415 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003416 {
3417 return;
3418 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003419 if constexpr (bmcwebEnableMultiHost)
3420 {
3421 // Option currently returns no systems. TBD
3422 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3423 systemName);
3424 return;
3425 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003426 if (systemName != "system")
3427 {
3428 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3429 systemName);
3430 return;
3431 }
3432
George Liu7a1dbc42022-12-07 16:03:22 +08003433 constexpr std::array<std::string_view, 1> interfaces = {
3434 crashdumpInterface};
3435 dbus::utility::getSubTreePaths(
3436 "/", 0, interfaces,
3437 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003438 const std::vector<std::string>& resp) {
3439 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003440 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003441 if (ec.value() !=
3442 boost::system::errc::no_such_file_or_directory)
3443 {
Ed Tanous62598e32023-07-17 17:06:25 -07003444 BMCWEB_LOG_DEBUG("failed to get entries ec: {}",
3445 ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003446 messages::internalError(asyncResp->res);
3447 return;
3448 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003449 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003450 asyncResp->res.jsonValue["@odata.type"] =
3451 "#LogEntryCollection.LogEntryCollection";
3452 asyncResp->res.jsonValue["@odata.id"] =
3453 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3454 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3455 asyncResp->res.jsonValue["Description"] =
3456 "Collection of Crashdump Entries";
3457 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3458 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003459
Ed Tanous002d39b2022-05-31 08:59:27 -07003460 for (const std::string& path : resp)
3461 {
3462 const sdbusplus::message::object_path objPath(path);
3463 // Get the log ID
3464 std::string logID = objPath.filename();
3465 if (logID.empty())
3466 {
3467 continue;
3468 }
3469 // Add the log entry to the array
3470 logCrashdumpEntry(asyncResp, logID,
3471 asyncResp->res.jsonValue["Members"]);
3472 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003473 });
Patrick Williams5a39f772023-10-20 11:20:21 -05003474 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003475}
Ed Tanous1da66f72018-07-27 16:13:37 -07003476
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003477inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003478{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003479 // Note: Deviated from redfish privilege registry for GET & HEAD
3480 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003481
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003482 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003483 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003484 // this is incorrect, should be
3485 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003486 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003487 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003488 [&app](const crow::Request& req,
3489 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003490 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003491 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003492 {
3493 return;
3494 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003495 if constexpr (bmcwebEnableMultiHost)
3496 {
3497 // Option currently returns no systems. TBD
3498 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3499 systemName);
3500 return;
3501 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003502 if (systemName != "system")
3503 {
3504 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3505 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003506 return;
3507 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003508 const std::string& logID = param;
3509 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
Patrick Williams5a39f772023-10-20 11:20:21 -05003510 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003511}
Ed Tanous1da66f72018-07-27 16:13:37 -07003512
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003513inline void requestRoutesCrashdumpFile(App& app)
3514{
3515 // Note: Deviated from redfish privilege registry for GET & HEAD
3516 // method for security reasons.
3517 BMCWEB_ROUTE(
3518 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003519 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003520 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003521 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003522 [](const crow::Request& req,
3523 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003524 const std::string& systemName, const std::string& logID,
3525 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003526 // Do not call getRedfishRoute here since the crashdump file is not a
3527 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003528
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003529 if constexpr (bmcwebEnableMultiHost)
3530 {
3531 // Option currently returns no systems. TBD
3532 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3533 systemName);
3534 return;
3535 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003536 if (systemName != "system")
3537 {
3538 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3539 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003540 return;
3541 }
3542
Ed Tanous002d39b2022-05-31 08:59:27 -07003543 auto getStoredLogCallback =
Ed Tanous39662a32023-02-06 15:09:46 -08003544 [asyncResp, logID, fileName, url(boost::urls::url(req.url()))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003545 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003546 const std::vector<
3547 std::pair<std::string, dbus::utility::DbusVariantType>>&
3548 resp) {
3549 if (ec)
3550 {
Ed Tanous62598e32023-07-17 17:06:25 -07003551 BMCWEB_LOG_DEBUG("failed to get log ec: {}", ec.message());
Ed Tanous002d39b2022-05-31 08:59:27 -07003552 messages::internalError(asyncResp->res);
3553 return;
3554 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003555
Ed Tanous002d39b2022-05-31 08:59:27 -07003556 std::string dbusFilename{};
3557 std::string dbusTimestamp{};
3558 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003559
Ed Tanous002d39b2022-05-31 08:59:27 -07003560 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3561 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003562
Ed Tanous002d39b2022-05-31 08:59:27 -07003563 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3564 dbusFilepath.empty())
3565 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003566 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003567 return;
3568 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003569
Ed Tanous002d39b2022-05-31 08:59:27 -07003570 // Verify the file name parameter is correct
3571 if (fileName != dbusFilename)
3572 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003573 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003574 return;
3575 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003576
Ed Tanous27b0cf92023-08-07 12:02:40 -07003577 if (!asyncResp->res.openFile(dbusFilepath))
Ed Tanous002d39b2022-05-31 08:59:27 -07003578 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003579 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003580 return;
3581 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003582
Ed Tanous002d39b2022-05-31 08:59:27 -07003583 // Configure this to be a file download when accessed
3584 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003585 asyncResp->res.addHeader(
3586 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003587 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003588 sdbusplus::asio::getAllProperties(
3589 *crow::connections::systemBus, crashdumpObject,
3590 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3591 std::move(getStoredLogCallback));
Patrick Williams5a39f772023-10-20 11:20:21 -05003592 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003593}
3594
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003595enum class OEMDiagnosticType
3596{
3597 onDemand,
3598 telemetry,
3599 invalid,
3600};
3601
Ed Tanous26ccae32023-02-16 10:28:44 -08003602inline OEMDiagnosticType getOEMDiagnosticType(std::string_view oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003603{
3604 if (oemDiagStr == "OnDemand")
3605 {
3606 return OEMDiagnosticType::onDemand;
3607 }
3608 if (oemDiagStr == "Telemetry")
3609 {
3610 return OEMDiagnosticType::telemetry;
3611 }
3612
3613 return OEMDiagnosticType::invalid;
3614}
3615
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003616inline void requestRoutesCrashdumpCollect(App& app)
3617{
3618 // Note: Deviated from redfish privilege registry for GET & HEAD
3619 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003620 BMCWEB_ROUTE(
3621 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003622 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003623 // The below is incorrect; Should be ConfigureManager
3624 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003625 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003626 .methods(boost::beast::http::verb::post)(
3627 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003628 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3629 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003630 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003631 {
3632 return;
3633 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003634
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003635 if constexpr (bmcwebEnableMultiHost)
3636 {
3637 // Option currently returns no systems. TBD
3638 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3639 systemName);
3640 return;
3641 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003642 if (systemName != "system")
3643 {
3644 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3645 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003646 return;
3647 }
3648
Ed Tanous002d39b2022-05-31 08:59:27 -07003649 std::string diagnosticDataType;
3650 std::string oemDiagnosticDataType;
3651 if (!redfish::json_util::readJsonAction(
3652 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3653 "OEMDiagnosticDataType", oemDiagnosticDataType))
3654 {
3655 return;
3656 }
3657
3658 if (diagnosticDataType != "OEM")
3659 {
Ed Tanous62598e32023-07-17 17:06:25 -07003660 BMCWEB_LOG_ERROR(
3661 "Only OEM DiagnosticDataType supported for Crashdump");
Ed Tanous002d39b2022-05-31 08:59:27 -07003662 messages::actionParameterValueFormatError(
3663 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3664 "CollectDiagnosticData");
3665 return;
3666 }
3667
3668 OEMDiagnosticType oemDiagType =
3669 getOEMDiagnosticType(oemDiagnosticDataType);
3670
3671 std::string iface;
3672 std::string method;
3673 std::string taskMatchStr;
3674 if (oemDiagType == OEMDiagnosticType::onDemand)
3675 {
3676 iface = crashdumpOnDemandInterface;
3677 method = "GenerateOnDemandLog";
3678 taskMatchStr = "type='signal',"
3679 "interface='org.freedesktop.DBus.Properties',"
3680 "member='PropertiesChanged',"
3681 "arg0namespace='com.intel.crashdump'";
3682 }
3683 else if (oemDiagType == OEMDiagnosticType::telemetry)
3684 {
3685 iface = crashdumpTelemetryInterface;
3686 method = "GenerateTelemetryLog";
3687 taskMatchStr = "type='signal',"
3688 "interface='org.freedesktop.DBus.Properties',"
3689 "member='PropertiesChanged',"
3690 "arg0namespace='com.intel.crashdump'";
3691 }
3692 else
3693 {
Ed Tanous62598e32023-07-17 17:06:25 -07003694 BMCWEB_LOG_ERROR("Unsupported OEMDiagnosticDataType: {}",
3695 oemDiagnosticDataType);
Ed Tanous002d39b2022-05-31 08:59:27 -07003696 messages::actionParameterValueFormatError(
3697 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3698 "CollectDiagnosticData");
3699 return;
3700 }
3701
3702 auto collectCrashdumpCallback =
3703 [asyncResp, payload(task::Payload(req)),
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003704 taskMatchStr](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003705 const std::string&) mutable {
3706 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003707 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003708 if (ec.value() == boost::system::errc::operation_not_supported)
3709 {
3710 messages::resourceInStandby(asyncResp->res);
3711 }
3712 else if (ec.value() ==
3713 boost::system::errc::device_or_resource_busy)
3714 {
3715 messages::serviceTemporarilyUnavailable(asyncResp->res,
3716 "60");
3717 }
3718 else
3719 {
3720 messages::internalError(asyncResp->res);
3721 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003722 return;
3723 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003724 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Ed Tanous8b242752023-06-27 17:17:13 -07003725 [](const boost::system::error_code& ec2, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003726 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous8b242752023-06-27 17:17:13 -07003727 if (!ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -07003728 {
3729 taskData->messages.emplace_back(messages::taskCompletedOK(
3730 std::to_string(taskData->index)));
3731 taskData->state = "Completed";
3732 }
3733 return task::completed;
Patrick Williams5a39f772023-10-20 11:20:21 -05003734 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003735 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003736
Ed Tanous002d39b2022-05-31 08:59:27 -07003737 task->startTimer(std::chrono::minutes(5));
3738 task->populateResp(asyncResp->res);
3739 task->payload.emplace(std::move(payload));
3740 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003741
Ed Tanous002d39b2022-05-31 08:59:27 -07003742 crow::connections::systemBus->async_method_call(
3743 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3744 iface, method);
Patrick Williams5a39f772023-10-20 11:20:21 -05003745 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003746}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003747
Andrew Geisslercb92c032018-08-17 07:56:14 -07003748/**
3749 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3750 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003751inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003752{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003753 /**
3754 * Function handles POST method request.
3755 * The Clear Log actions does not require any parameter.The action deletes
3756 * all entries found in the Entries collection for this Log Service.
3757 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003758
George Liu0fda0f12021-11-16 10:06:17 +08003759 BMCWEB_ROUTE(
3760 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003761 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003762 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003763 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003764 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003765 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3766 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003767 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003768 {
3769 return;
3770 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003771 if constexpr (bmcwebEnableMultiHost)
3772 {
3773 // Option currently returns no systems. TBD
3774 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3775 systemName);
3776 return;
3777 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003778 if (systemName != "system")
3779 {
3780 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3781 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003782 return;
3783 }
Ed Tanous62598e32023-07-17 17:06:25 -07003784 BMCWEB_LOG_DEBUG("Do delete all entries.");
Andrew Geisslercb92c032018-08-17 07:56:14 -07003785
Ed Tanous002d39b2022-05-31 08:59:27 -07003786 // Process response from Logging service.
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003787 auto respHandler = [asyncResp](const boost::system::error_code& ec) {
Ed Tanous62598e32023-07-17 17:06:25 -07003788 BMCWEB_LOG_DEBUG("doClearLog resp_handler callback: Done");
Ed Tanous002d39b2022-05-31 08:59:27 -07003789 if (ec)
3790 {
3791 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003792 BMCWEB_LOG_ERROR("doClearLog resp_handler got error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003793 asyncResp->res.result(
3794 boost::beast::http::status::internal_server_error);
3795 return;
3796 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003797
Ed Tanous002d39b2022-05-31 08:59:27 -07003798 asyncResp->res.result(boost::beast::http::status::no_content);
3799 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003800
Ed Tanous002d39b2022-05-31 08:59:27 -07003801 // Make call to Logging service to request Clear Log
3802 crow::connections::systemBus->async_method_call(
3803 respHandler, "xyz.openbmc_project.Logging",
3804 "/xyz/openbmc_project/logging",
3805 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003806 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003807}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003808
3809/****************************************************
3810 * Redfish PostCode interfaces
3811 * using DBUS interface: getPostCodesTS
3812 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003813inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003814{
Ed Tanous22d268c2022-05-19 09:39:07 -07003815 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003816 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003817 .methods(boost::beast::http::verb::get)(
3818 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003819 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3820 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003821 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003822 {
3823 return;
3824 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003825 if constexpr (bmcwebEnableMultiHost)
3826 {
3827 // Option currently returns no systems. TBD
3828 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3829 systemName);
3830 return;
3831 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003832 if (systemName != "system")
3833 {
3834 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3835 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003836 return;
3837 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003838 asyncResp->res.jsonValue["@odata.id"] =
3839 "/redfish/v1/Systems/system/LogServices/PostCodes";
3840 asyncResp->res.jsonValue["@odata.type"] =
Janet Adkinsb25644a2023-08-16 11:23:45 -05003841 "#LogService.v1_2_0.LogService";
Ed Tanous002d39b2022-05-31 08:59:27 -07003842 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3843 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
Ed Tanoused34a4a2023-02-08 15:43:27 -08003844 asyncResp->res.jsonValue["Id"] = "PostCodes";
Ed Tanous002d39b2022-05-31 08:59:27 -07003845 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3846 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3847 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303848
Ed Tanous002d39b2022-05-31 08:59:27 -07003849 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003850 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003851 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3852 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3853 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303854
Ed Tanous002d39b2022-05-31 08:59:27 -07003855 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3856 {"target",
3857 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
Patrick Williams5a39f772023-10-20 11:20:21 -05003858 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003859}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003860
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003861inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003862{
George Liu0fda0f12021-11-16 10:06:17 +08003863 BMCWEB_ROUTE(
3864 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003865 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003866 // The following privilege is incorrect; It should be ConfigureManager
3867 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003868 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003869 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003870 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003871 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3872 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003873 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003874 {
3875 return;
3876 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08003877 if constexpr (bmcwebEnableMultiHost)
3878 {
3879 // Option currently returns no systems. TBD
3880 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3881 systemName);
3882 return;
3883 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003884 if (systemName != "system")
3885 {
3886 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3887 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003888 return;
3889 }
Ed Tanous62598e32023-07-17 17:06:25 -07003890 BMCWEB_LOG_DEBUG("Do delete all postcodes entries.");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003891
Ed Tanous002d39b2022-05-31 08:59:27 -07003892 // Make call to post-code service to request clear all
3893 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08003894 [asyncResp](const boost::system::error_code& ec) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003895 if (ec)
3896 {
3897 // TODO Handle for specific error code
Ed Tanous62598e32023-07-17 17:06:25 -07003898 BMCWEB_LOG_ERROR("doClearPostCodes resp_handler got error {}",
3899 ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07003900 asyncResp->res.result(
3901 boost::beast::http::status::internal_server_error);
3902 messages::internalError(asyncResp->res);
3903 return;
3904 }
Tony Lee18fc70c2023-08-24 16:15:54 +08003905 messages::success(asyncResp->res);
Patrick Williams5a39f772023-10-20 11:20:21 -05003906 },
Ed Tanous002d39b2022-05-31 08:59:27 -07003907 "xyz.openbmc_project.State.Boot.PostCode0",
3908 "/xyz/openbmc_project/State/Boot/PostCode0",
3909 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
Patrick Williams5a39f772023-10-20 11:20:21 -05003910 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003911}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003912
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003913/**
3914 * @brief Parse post code ID and get the current value and index value
3915 * eg: postCodeID=B1-2, currentValue=1, index=2
3916 *
3917 * @param[in] postCodeID Post Code ID
3918 * @param[out] currentValue Current value
3919 * @param[out] index Index value
3920 *
3921 * @return bool true if the parsing is successful, false the parsing fails
3922 */
Ed Tanousdf254f22024-04-01 13:25:46 -07003923inline bool parsePostCode(const std::string& postCodeID, uint64_t& currentValue,
3924 uint16_t& index)
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003925{
3926 std::vector<std::string> split;
Ed Tanous50ebd4a2023-01-19 19:03:17 -08003927 bmcweb::split(split, postCodeID, '-');
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003928 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3929 {
3930 return false;
3931 }
3932
Patrick Williams84396af2023-05-11 11:47:45 -05003933 auto start = std::next(split[0].begin());
3934 auto end = split[0].end();
3935 auto [ptrIndex, ecIndex] = std::from_chars(&*start, &*end, index);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003936
Patrick Williams84396af2023-05-11 11:47:45 -05003937 if (ptrIndex != &*end || ecIndex != std::errc())
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003938 {
3939 return false;
3940 }
3941
Patrick Williams84396af2023-05-11 11:47:45 -05003942 start = split[1].begin();
3943 end = split[1].end();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003944
Patrick Williams84396af2023-05-11 11:47:45 -05003945 auto [ptrValue, ecValue] = std::from_chars(&*start, &*end, currentValue);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003946
Patrick Williams84396af2023-05-11 11:47:45 -05003947 return ptrValue == &*end && ecValue == std::errc();
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003948}
3949
3950static bool fillPostCodeEntry(
Ed Tanousac106bf2023-06-07 09:24:59 -07003951 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303952 const boost::container::flat_map<
3953 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003954 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3955 const uint64_t skip = 0, const uint64_t top = 0)
3956{
3957 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003958 const registries::Message* message =
3959 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003960
3961 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003962 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303963 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3964 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003965 {
3966 currentCodeIndex++;
3967 std::string postcodeEntryID =
3968 "B" + std::to_string(bootIndex) + "-" +
3969 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3970
3971 uint64_t usecSinceEpoch = code.first;
3972 uint64_t usTimeOffset = 0;
3973
3974 if (1 == currentCodeIndex)
3975 { // already incremented
3976 firstCodeTimeUs = code.first;
3977 }
3978 else
3979 {
3980 usTimeOffset = code.first - firstCodeTimeUs;
3981 }
3982
3983 // skip if no specific codeIndex is specified and currentCodeIndex does
3984 // not fall between top and skip
3985 if ((codeIndex == 0) &&
3986 (currentCodeIndex <= skip || currentCodeIndex > top))
3987 {
3988 continue;
3989 }
3990
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003991 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003992 // currentIndex
3993 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3994 {
3995 // This is done for simplicity. 1st entry is needed to calculate
3996 // time offset. To improve efficiency, one can get to the entry
3997 // directly (possibly with flatmap's nth method)
3998 continue;
3999 }
4000
4001 // currentCodeIndex is within top and skip or equal to specified code
4002 // index
4003
4004 // Get the Created time from the timestamp
4005 std::string entryTimeStr;
Konstantin Aladyshev2a025612023-02-15 11:52:58 +03004006 entryTimeStr = redfish::time_utils::getDateTimeUintUs(usecSinceEpoch);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004007
4008 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
4009 std::ostringstream hexCode;
4010 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304011 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004012 std::ostringstream timeOffsetStr;
4013 // Set Fixed -Point Notation
4014 timeOffsetStr << std::fixed;
4015 // Set precision to 4 digits
4016 timeOffsetStr << std::setprecision(4);
4017 // Add double to stream
4018 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004019
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004020 std::string bootIndexStr = std::to_string(bootIndex);
4021 std::string timeOffsetString = timeOffsetStr.str();
4022 std::string hexCodeStr = hexCode.str();
4023
4024 std::array<std::string_view, 3> messageArgs = {
4025 bootIndexStr, timeOffsetString, hexCodeStr};
4026
4027 std::string msg =
4028 redfish::registries::fillMessageArgs(messageArgs, message->message);
4029 if (msg.empty())
ZhikuiRena3316fc2020-01-29 14:58:08 -08004030 {
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004031 messages::internalError(asyncResp->res);
4032 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004033 }
4034
Tim Leed4342a92020-04-27 11:47:58 +08004035 // Get Severity template from message registry
4036 std::string severity;
4037 if (message != nullptr)
4038 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08004039 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08004040 }
4041
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004042 // Format entry
4043 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05004044 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanousef4c65b2023-04-24 15:28:50 -07004045 bmcLogEntry["@odata.id"] = boost::urls::format(
4046 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/{}",
4047 postcodeEntryID);
Jason M. Bills84afc482022-06-24 12:38:23 -07004048 bmcLogEntry["Name"] = "POST Code Log Entry";
4049 bmcLogEntry["Id"] = postcodeEntryID;
4050 bmcLogEntry["Message"] = std::move(msg);
4051 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
Ed Tanous1e6deaf2022-02-17 11:32:37 -08004052 bmcLogEntry["MessageArgs"] = messageArgs;
Jason M. Bills84afc482022-06-24 12:38:23 -07004053 bmcLogEntry["EntryType"] = "Event";
4054 bmcLogEntry["Severity"] = std::move(severity);
4055 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08004056 if (!std::get<std::vector<uint8_t>>(code.second).empty())
4057 {
4058 bmcLogEntry["AdditionalDataURI"] =
4059 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
4060 postcodeEntryID + "/attachment";
4061 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004062
4063 // codeIndex is only specified when querying single entry, return only
4064 // that entry in this case
4065 if (codeIndex != 0)
4066 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004067 asyncResp->res.jsonValue.update(bmcLogEntry);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004068 return true;
4069 }
4070
Ed Tanousac106bf2023-06-07 09:24:59 -07004071 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Patrick Williamsb2ba3072023-05-12 10:27:39 -05004072 logEntryArray.emplace_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08004073 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004074
4075 // Return value is always false when querying multiple entries
4076 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004077}
4078
Ed Tanousac106bf2023-06-07 09:24:59 -07004079static void
4080 getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4081 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004082{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004083 uint16_t bootIndex = 0;
4084 uint64_t codeIndex = 0;
4085 if (!parsePostCode(entryId, codeIndex, bootIndex))
4086 {
4087 // Requested ID was not found
Ed Tanousac106bf2023-06-07 09:24:59 -07004088 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004089 return;
4090 }
4091
4092 if (bootIndex == 0 || codeIndex == 0)
4093 {
4094 // 0 is an invalid index
Ed Tanousac106bf2023-06-07 09:24:59 -07004095 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004096 return;
4097 }
4098
ZhikuiRena3316fc2020-01-29 14:58:08 -08004099 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004100 [asyncResp, entryId, bootIndex,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004101 codeIndex](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304102 const boost::container::flat_map<
4103 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4104 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004105 if (ec)
4106 {
Ed Tanous62598e32023-07-17 17:06:25 -07004107 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004108 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004109 return;
4110 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004111
Ed Tanous002d39b2022-05-31 08:59:27 -07004112 if (postcode.empty())
4113 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004114 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07004115 return;
4116 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004117
Ed Tanousac106bf2023-06-07 09:24:59 -07004118 if (!fillPostCodeEntry(asyncResp, postcode, bootIndex, codeIndex))
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004119 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004120 messages::resourceNotFound(asyncResp->res, "LogEntry", entryId);
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004121 return;
4122 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004123 },
Jonathan Doman15124762021-01-07 17:54:17 -08004124 "xyz.openbmc_project.State.Boot.PostCode0",
4125 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004126 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4127 bootIndex);
4128}
4129
Ed Tanousac106bf2023-06-07 09:24:59 -07004130static void
4131 getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4132 const uint16_t bootIndex, const uint16_t bootCount,
4133 const uint64_t entryCount, size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004134{
4135 crow::connections::systemBus->async_method_call(
Ed Tanousac106bf2023-06-07 09:24:59 -07004136 [asyncResp, bootIndex, bootCount, entryCount, skip,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004137 top](const boost::system::error_code& ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05304138 const boost::container::flat_map<
4139 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
4140 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004141 if (ec)
4142 {
Ed Tanous62598e32023-07-17 17:06:25 -07004143 BMCWEB_LOG_DEBUG("DBUS POST CODE PostCode response error");
Ed Tanousac106bf2023-06-07 09:24:59 -07004144 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004145 return;
4146 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004147
Ed Tanous002d39b2022-05-31 08:59:27 -07004148 uint64_t endCount = entryCount;
4149 if (!postcode.empty())
4150 {
4151 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07004152 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004153 {
Patrick Williams89492a12023-05-10 07:51:34 -05004154 uint64_t thisBootSkip = std::max(static_cast<uint64_t>(skip),
4155 entryCount) -
4156 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004157 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07004158 std::min(static_cast<uint64_t>(top + skip), endCount) -
4159 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004160
Ed Tanousac106bf2023-06-07 09:24:59 -07004161 fillPostCodeEntry(asyncResp, postcode, bootIndex, 0,
4162 thisBootSkip, thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08004163 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004164 asyncResp->res.jsonValue["Members@odata.count"] = endCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07004165 }
4166
4167 // continue to previous bootIndex
4168 if (bootIndex < bootCount)
4169 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004170 getPostCodeForBoot(asyncResp, static_cast<uint16_t>(bootIndex + 1),
Ed Tanous002d39b2022-05-31 08:59:27 -07004171 bootCount, endCount, skip, top);
4172 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08004173 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07004174 {
Ed Tanousac106bf2023-06-07 09:24:59 -07004175 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Ed Tanous002d39b2022-05-31 08:59:27 -07004176 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
4177 std::to_string(skip + top);
4178 }
Patrick Williams5a39f772023-10-20 11:20:21 -05004179 },
Jonathan Doman15124762021-01-07 17:54:17 -08004180 "xyz.openbmc_project.State.Boot.PostCode0",
4181 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08004182 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
4183 bootIndex);
4184}
4185
zhanghch058d1b46d2021-04-01 11:18:24 +08004186static void
Ed Tanousac106bf2023-06-07 09:24:59 -07004187 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07004188 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004189{
4190 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07004191 sdbusplus::asio::getProperty<uint16_t>(
4192 *crow::connections::systemBus,
4193 "xyz.openbmc_project.State.Boot.PostCode0",
4194 "/xyz/openbmc_project/State/Boot/PostCode0",
4195 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
Ed Tanousac106bf2023-06-07 09:24:59 -07004196 [asyncResp, entryCount, skip, top](const boost::system::error_code& ec,
4197 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004198 if (ec)
4199 {
Ed Tanous62598e32023-07-17 17:06:25 -07004200 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanousac106bf2023-06-07 09:24:59 -07004201 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -07004202 return;
4203 }
Ed Tanousac106bf2023-06-07 09:24:59 -07004204 getPostCodeForBoot(asyncResp, 1, bootCount, entryCount, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004205 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08004206}
4207
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004208inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004209{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004210 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004211 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07004212 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004213 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004214 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07004215 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4216 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07004217 query_param::QueryCapabilities capabilities = {
4218 .canDelegateTop = true,
4219 .canDelegateSkip = true,
4220 };
4221 query_param::Query delegatedQuery;
4222 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00004223 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07004224 {
4225 return;
4226 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004227 if constexpr (bmcwebEnableMultiHost)
4228 {
4229 // Option currently returns no systems. TBD
4230 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4231 systemName);
4232 return;
4233 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004234
4235 if (systemName != "system")
4236 {
4237 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4238 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004239 return;
4240 }
Ed Tanous002d39b2022-05-31 08:59:27 -07004241 asyncResp->res.jsonValue["@odata.type"] =
4242 "#LogEntryCollection.LogEntryCollection";
4243 asyncResp->res.jsonValue["@odata.id"] =
4244 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
4245 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4246 asyncResp->res.jsonValue["Description"] =
4247 "Collection of POST Code Log Entries";
4248 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4249 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07004250 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08004251 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07004252 getCurrentBootNumber(asyncResp, skip, top);
Patrick Williams5a39f772023-10-20 11:20:21 -05004253 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004254}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004255
George Liu647b3cd2021-07-05 12:43:56 +08004256inline void requestRoutesPostCodesEntryAdditionalData(App& app)
4257{
George Liu0fda0f12021-11-16 10:06:17 +08004258 BMCWEB_ROUTE(
4259 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07004260 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08004261 .privileges(redfish::privileges::getLogEntry)
4262 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004263 [&app](const crow::Request& req,
4264 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004265 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07004266 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004267 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004268 {
4269 return;
4270 }
Matt Spinler72e21372023-04-19 12:53:33 -05004271 if (!http_helpers::isContentTypeAllowed(
Ed Tanous99351cd2022-08-07 16:42:51 -07004272 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07004273 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07004274 {
4275 asyncResp->res.result(boost::beast::http::status::bad_request);
4276 return;
4277 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004278 if constexpr (bmcwebEnableMultiHost)
4279 {
4280 // Option currently returns no systems. TBD
4281 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4282 systemName);
4283 return;
4284 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004285 if (systemName != "system")
4286 {
4287 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4288 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07004289 return;
4290 }
George Liu647b3cd2021-07-05 12:43:56 +08004291
Ed Tanous002d39b2022-05-31 08:59:27 -07004292 uint64_t currentValue = 0;
4293 uint16_t index = 0;
4294 if (!parsePostCode(postCodeID, currentValue, index))
4295 {
4296 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
4297 return;
4298 }
George Liu647b3cd2021-07-05 12:43:56 +08004299
Ed Tanous002d39b2022-05-31 08:59:27 -07004300 crow::connections::systemBus->async_method_call(
4301 [asyncResp, postCodeID, currentValue](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -08004302 const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07004303 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
4304 postcodes) {
4305 if (ec.value() == EBADR)
4306 {
4307 messages::resourceNotFound(asyncResp->res, "LogEntry",
4308 postCodeID);
4309 return;
4310 }
4311 if (ec)
4312 {
Ed Tanous62598e32023-07-17 17:06:25 -07004313 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
Ed Tanous002d39b2022-05-31 08:59:27 -07004314 messages::internalError(asyncResp->res);
4315 return;
4316 }
George Liu647b3cd2021-07-05 12:43:56 +08004317
Ed Tanous002d39b2022-05-31 08:59:27 -07004318 size_t value = static_cast<size_t>(currentValue) - 1;
4319 if (value == std::string::npos || postcodes.size() < currentValue)
4320 {
Ed Tanous62598e32023-07-17 17:06:25 -07004321 BMCWEB_LOG_WARNING("Wrong currentValue value");
Ed Tanous002d39b2022-05-31 08:59:27 -07004322 messages::resourceNotFound(asyncResp->res, "LogEntry",
4323 postCodeID);
4324 return;
4325 }
George Liu647b3cd2021-07-05 12:43:56 +08004326
Ed Tanous002d39b2022-05-31 08:59:27 -07004327 const auto& [tID, c] = postcodes[value];
4328 if (c.empty())
4329 {
Ed Tanous62598e32023-07-17 17:06:25 -07004330 BMCWEB_LOG_WARNING("No found post code data");
Ed Tanous002d39b2022-05-31 08:59:27 -07004331 messages::resourceNotFound(asyncResp->res, "LogEntry",
4332 postCodeID);
4333 return;
4334 }
4335 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4336 const char* d = reinterpret_cast<const char*>(c.data());
4337 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004338
Ed Tanousd9f6c622022-03-17 09:12:17 -07004339 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004340 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004341 asyncResp->res.addHeader(
4342 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous27b0cf92023-08-07 12:02:40 -07004343 asyncResp->res.write(crow::utility::base64encode(strData));
Patrick Williams5a39f772023-10-20 11:20:21 -05004344 },
Ed Tanous002d39b2022-05-31 08:59:27 -07004345 "xyz.openbmc_project.State.Boot.PostCode0",
4346 "/xyz/openbmc_project/State/Boot/PostCode0",
4347 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
Patrick Williams5a39f772023-10-20 11:20:21 -05004348 });
George Liu647b3cd2021-07-05 12:43:56 +08004349}
4350
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004351inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004352{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004353 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004354 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004355 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004356 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004357 [&app](const crow::Request& req,
4358 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004359 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004360 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004361 {
4362 return;
4363 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -08004364 if constexpr (bmcwebEnableMultiHost)
4365 {
4366 // Option currently returns no systems. TBD
4367 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4368 systemName);
4369 return;
4370 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004371 if (systemName != "system")
4372 {
4373 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4374 systemName);
4375 return;
4376 }
4377
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004378 getPostCodeForEntry(asyncResp, targetID);
Patrick Williams5a39f772023-10-20 11:20:21 -05004379 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004380}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004381
Ed Tanous1da66f72018-07-27 16:13:37 -07004382} // namespace redfish