blob: 92954861d6d9ffe2c20756d262175aee795c96cc [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
Spencer Kub7028eb2021-10-26 15:27:35 +080018#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080019#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080020#include "human_sort.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070021#include "registries.hpp"
22#include "registries/base_message_registry.hpp"
23#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080024#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070025
Jason M. Billse1f26342018-07-18 12:12:00 -070026#include <systemd/sd-journal.h>
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060027#include <tinyxml2.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060028#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070029
John Edward Broadbent7e860f12021-04-08 15:57:16 -070030#include <app.hpp>
Ed Tanous9896eae2022-07-23 15:07:33 -070031#include <boost/algorithm/string/case_conv.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070032#include <boost/algorithm/string/classification.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060033#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070034#include <boost/algorithm/string/split.hpp>
Ed Tanous07c8c202022-07-11 10:08:08 -070035#include <boost/beast/http/verb.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070036#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080037#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080038#include <dbus_utility.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070039#include <error_messages.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070040#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070041#include <registries/privilege_registry.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020042#include <sdbusplus/asio/property.hpp>
43#include <sdbusplus/unpack_properties.hpp>
44#include <utils/dbus_utils.hpp>
Ed Tanous2b829372022-08-03 14:22:34 -070045#include <utils/time_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050046
George Liu647b3cd2021-07-05 12:43:56 +080047#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070048#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080049#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070050#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070051#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080052#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070053
54namespace redfish
55{
56
Gunnar Mills1214b7e2020-06-04 10:11:30 -050057constexpr char const* crashdumpObject = "com.intel.crashdump";
58constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050059constexpr char const* crashdumpInterface = "com.intel.crashdump";
60constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070061 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050062constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070063 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070064constexpr char const* crashdumpTelemetryInterface =
65 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070066
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060067enum class DumpCreationProgress
68{
69 DUMP_CREATE_SUCCESS,
70 DUMP_CREATE_FAILED,
71 DUMP_CREATE_INPROGRESS
72};
73
Ed Tanousfffb8c12022-02-07 23:53:03 -080074namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070075{
Ed Tanous26702d02021-11-03 15:02:33 -070076static const Message*
77 getMessageFromRegistry(const std::string& messageKey,
78 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070079{
Ed Tanous002d39b2022-05-31 08:59:27 -070080 std::span<const MessageEntry>::iterator messageIt =
81 std::find_if(registry.begin(), registry.end(),
82 [&messageKey](const MessageEntry& messageEntry) {
83 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070084 });
85 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070086 {
87 return &messageIt->second;
88 }
89
90 return nullptr;
91}
92
Gunnar Mills1214b7e2020-06-04 10:11:30 -050093static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070094{
95 // Redfish MessageIds are in the form
96 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
97 // the right Message
98 std::vector<std::string> fields;
99 fields.reserve(4);
100 boost::split(fields, messageID, boost::is_any_of("."));
Ed Tanous02cad962022-06-30 16:50:15 -0700101 const std::string& registryName = fields[0];
102 const std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -0700103
104 // Find the right registry and check it for the MessageKey
105 if (std::string(base::header.registryPrefix) == registryName)
106 {
107 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700108 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700109 }
110 if (std::string(openbmc::header.registryPrefix) == registryName)
111 {
112 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700113 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700114 }
115 return nullptr;
116}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800117} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700118
James Feistf6150402019-01-08 10:36:20 -0800119namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700120
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500121inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700122{
Ed Tanousd4d25792020-09-29 15:15:03 -0700123 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
124 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
125 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
126 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700127 {
128 return "Critical";
129 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700130 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
131 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
132 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700133 {
134 return "OK";
135 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700136 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700137 {
138 return "Warning";
139 }
140 return "";
141}
142
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700143inline static int getJournalMetadata(sd_journal* journal,
144 const std::string_view& field,
145 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700146{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500147 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700148 size_t length = 0;
149 int ret = 0;
150 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800151 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
152 const void** dataVoid = reinterpret_cast<const void**>(&data);
153
154 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700155 if (ret < 0)
156 {
157 return ret;
158 }
Ed Tanous39e77502019-03-04 17:35:53 -0800159 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700160 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000161 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700162 return ret;
163}
164
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165inline static int getJournalMetadata(sd_journal* journal,
166 const std::string_view& field,
167 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700168{
169 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800170 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700171 // Get the metadata from the requested field of the journal entry
172 ret = getJournalMetadata(journal, field, metadata);
173 if (ret < 0)
174 {
175 return ret;
176 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000177 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700178 return ret;
179}
180
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700181inline static bool getEntryTimestamp(sd_journal* journal,
182 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800183{
184 int ret = 0;
185 uint64_t timestamp = 0;
186 ret = sd_journal_get_realtime_usec(journal, &timestamp);
187 if (ret < 0)
188 {
189 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
190 << strerror(-ret);
191 return false;
192 }
Ed Tanous2b829372022-08-03 14:22:34 -0700193 entryTimestamp =
194 redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500195 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800196}
Ed Tanous50b8a432022-02-03 16:29:50 -0800197
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700198inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
199 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700200{
201 int ret = 0;
202 static uint64_t prevTs = 0;
203 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700204 if (firstEntry)
205 {
206 prevTs = 0;
207 }
208
Jason M. Bills16428a12018-11-02 12:42:29 -0700209 // Get the entry timestamp
210 uint64_t curTs = 0;
211 ret = sd_journal_get_realtime_usec(journal, &curTs);
212 if (ret < 0)
213 {
214 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
215 << strerror(-ret);
216 return false;
217 }
218 // If the timestamp isn't unique, increment the index
219 if (curTs == prevTs)
220 {
221 index++;
222 }
223 else
224 {
225 // Otherwise, reset it
226 index = 0;
227 }
228 // Save the timestamp
229 prevTs = curTs;
230
231 entryID = std::to_string(curTs);
232 if (index > 0)
233 {
234 entryID += "_" + std::to_string(index);
235 }
236 return true;
237}
238
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500239static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700240 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700241{
Ed Tanous271584a2019-07-09 16:24:22 -0700242 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700243 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700244 if (firstEntry)
245 {
246 prevTs = 0;
247 }
248
Jason M. Bills95820182019-04-22 16:25:34 -0700249 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700250 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700251 std::tm timeStruct = {};
252 std::istringstream entryStream(logEntry);
253 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
254 {
255 curTs = std::mktime(&timeStruct);
256 }
257 // If the timestamp isn't unique, increment the index
258 if (curTs == prevTs)
259 {
260 index++;
261 }
262 else
263 {
264 // Otherwise, reset it
265 index = 0;
266 }
267 // Save the timestamp
268 prevTs = curTs;
269
270 entryID = std::to_string(curTs);
271 if (index > 0)
272 {
273 entryID += "_" + std::to_string(index);
274 }
275 return true;
276}
277
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700278inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800279 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
280 const std::string& entryID, uint64_t& timestamp,
281 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700282{
283 if (entryID.empty())
284 {
285 return false;
286 }
287 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800288 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700289
Ed Tanous81ce6092020-12-17 16:54:55 +0000290 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800291 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700292 {
293 // Timestamp has an index
294 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800295 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700296 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700297 auto [ptr, ec] = std::from_chars(
298 indexStr.data(), indexStr.data() + indexStr.size(), index);
299 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700300 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800301 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700302 return false;
303 }
304 }
305 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700306 auto [ptr, ec] =
307 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
308 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700309 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800310 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700311 return false;
312 }
313 return true;
314}
315
Jason M. Bills95820182019-04-22 16:25:34 -0700316static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500317 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700318{
319 static const std::filesystem::path redfishLogDir = "/var/log";
320 static const std::string redfishLogFilename = "redfish";
321
322 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500323 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700324 std::filesystem::directory_iterator(redfishLogDir))
325 {
326 // If we find a redfish log file, save the path
327 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700328 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700329 {
330 redfishLogFiles.emplace_back(redfishLogDir / filename);
331 }
332 }
333 // As the log files rotate, they are appended with a ".#" that is higher for
334 // the older logs. Since we don't expect more than 10 log files, we
335 // can just sort the list to get them in order from newest to oldest
336 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
337
338 return !redfishLogFiles.empty();
339}
340
Claire Weinanaefe3782022-07-15 19:17:19 -0700341inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800342 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700343 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700344 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
345{
346 for (const auto& interfaceMap : object.second)
347 {
348 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
349 {
350 for (const auto& propertyMap : interfaceMap.second)
351 {
352 if (propertyMap.first == "Status")
353 {
354 const auto* status =
355 std::get_if<std::string>(&propertyMap.second);
356 if (status == nullptr)
357 {
358 messages::internalError(asyncResp->res);
359 break;
360 }
361 dumpStatus = *status;
362 }
363 }
364 }
365 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
366 {
367 for (const auto& propertyMap : interfaceMap.second)
368 {
369 if (propertyMap.first == "Size")
370 {
371 const auto* sizePtr =
372 std::get_if<uint64_t>(&propertyMap.second);
373 if (sizePtr == nullptr)
374 {
375 messages::internalError(asyncResp->res);
376 break;
377 }
378 size = *sizePtr;
379 break;
380 }
381 }
382 }
383 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
384 {
385 for (const auto& propertyMap : interfaceMap.second)
386 {
387 if (propertyMap.first == "Elapsed")
388 {
389 const uint64_t* usecsTimeStamp =
390 std::get_if<uint64_t>(&propertyMap.second);
391 if (usecsTimeStamp == nullptr)
392 {
393 messages::internalError(asyncResp->res);
394 break;
395 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700396 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700397 break;
398 }
399 }
400 }
401 }
402}
403
Nan Zhou21ab4042022-06-26 23:07:40 +0000404static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800405{
406 std::string entriesPath;
407
408 if (dumpType == "BMC")
409 {
410 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
411 }
412 else if (dumpType == "FaultLog")
413 {
414 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
415 }
416 else if (dumpType == "System")
417 {
418 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
419 }
420 else
421 {
422 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
423 << dumpType;
424 }
425
426 // Returns empty string on error
427 return entriesPath;
428}
429
zhanghch058d1b46d2021-04-01 11:18:24 +0800430inline void
431 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
432 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500433{
Claire Weinanfdd26902022-03-01 14:18:25 -0800434 std::string entriesPath = getDumpEntriesPath(dumpType);
435 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500436 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500437 messages::internalError(asyncResp->res);
438 return;
439 }
440
441 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800442 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800443 dumpType](const boost::system::error_code ec,
444 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700445 if (ec)
446 {
447 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
448 messages::internalError(asyncResp->res);
449 return;
450 }
451
Claire Weinanfdd26902022-03-01 14:18:25 -0800452 // Remove ending slash
453 std::string odataIdStr = entriesPath;
454 if (!odataIdStr.empty())
455 {
456 odataIdStr.pop_back();
457 }
458
459 asyncResp->res.jsonValue["@odata.type"] =
460 "#LogEntryCollection.LogEntryCollection";
461 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
462 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
463 asyncResp->res.jsonValue["Description"] =
464 "Collection of " + dumpType + " Dump Entries";
465
Ed Tanous002d39b2022-05-31 08:59:27 -0700466 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
467 entriesArray = nlohmann::json::array();
468 std::string dumpEntryPath =
469 "/xyz/openbmc_project/dump/" +
470 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
471
472 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
473 return AlphanumLess<std::string>()(l.first.filename(),
474 r.first.filename());
475 });
476
477 for (auto& object : resp)
478 {
479 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500480 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 continue;
482 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700483 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 uint64_t size = 0;
485 std::string dumpStatus;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700486 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700487
488 std::string entryID = object.first.filename();
489 if (entryID.empty())
490 {
491 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500492 }
493
Claire Weinanc6fecda2022-07-15 10:43:25 -0700494 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700495 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700496
497 if (dumpStatus !=
498 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
499 !dumpStatus.empty())
500 {
501 // Dump status is not Complete, no need to enumerate
502 continue;
503 }
504
Vijay Lobo9c11a172021-10-07 16:53:16 -0500505 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800506 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 thisEntry["Id"] = entryID;
508 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700509 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700510 thisEntry["Created"] =
511 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700512
Ed Tanous002d39b2022-05-31 08:59:27 -0700513 if (dumpType == "BMC")
514 {
515 thisEntry["DiagnosticDataType"] = "Manager";
516 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800517 entriesPath + entryID + "/attachment";
518 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700519 }
520 else if (dumpType == "System")
521 {
522 thisEntry["DiagnosticDataType"] = "OEM";
523 thisEntry["OEMDiagnosticDataType"] = "System";
524 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800525 entriesPath + entryID + "/attachment";
526 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700527 }
528 entriesArray.push_back(std::move(thisEntry));
529 }
530 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500531 },
532 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
533 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
534}
535
zhanghch058d1b46d2021-04-01 11:18:24 +0800536inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700537 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800538 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500539{
Claire Weinanfdd26902022-03-01 14:18:25 -0800540 std::string entriesPath = getDumpEntriesPath(dumpType);
541 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500542 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500543 messages::internalError(asyncResp->res);
544 return;
545 }
546
547 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800548 [asyncResp, entryID, dumpType,
549 entriesPath](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700550 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700551 if (ec)
552 {
553 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
554 messages::internalError(asyncResp->res);
555 return;
556 }
557
558 bool foundDumpEntry = false;
559 std::string dumpEntryPath =
560 "/xyz/openbmc_project/dump/" +
561 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
562
563 for (const auto& objectPath : resp)
564 {
565 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500566 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700567 continue;
568 }
569
570 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700571 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700572 uint64_t size = 0;
573 std::string dumpStatus;
574
Claire Weinanaefe3782022-07-15 19:17:19 -0700575 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700576 timestampUs, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700577
578 if (dumpStatus !=
579 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
580 !dumpStatus.empty())
581 {
582 // Dump status is not Complete
583 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200584 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
585 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500586 return;
587 }
588
Ed Tanous002d39b2022-05-31 08:59:27 -0700589 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -0500590 "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800591 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700592 asyncResp->res.jsonValue["Id"] = entryID;
593 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700594 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700595 asyncResp->res.jsonValue["Created"] =
596 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500597
Ed Tanous002d39b2022-05-31 08:59:27 -0700598 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500599 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700600 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
601 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800602 entriesPath + entryID + "/attachment";
603 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500604 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500606 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700607 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
608 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
609 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800610 entriesPath + entryID + "/attachment";
611 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500612 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 }
614 if (!foundDumpEntry)
615 {
616 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
617 messages::internalError(asyncResp->res);
618 return;
619 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500620 },
621 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
622 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
623}
624
zhanghch058d1b46d2021-04-01 11:18:24 +0800625inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800626 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500627 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500628{
Ed Tanous002d39b2022-05-31 08:59:27 -0700629 auto respHandler =
630 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500631 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
632 if (ec)
633 {
George Liu3de8d8b2021-03-22 17:49:39 +0800634 if (ec.value() == EBADR)
635 {
636 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
637 return;
638 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800640 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500641 messages::internalError(asyncResp->res);
642 return;
643 }
644 };
645 crow::connections::systemBus->async_method_call(
646 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500647 "/xyz/openbmc_project/dump/" +
648 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
649 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500650 "xyz.openbmc_project.Object.Delete", "Delete");
651}
652
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600653inline DumpCreationProgress
654 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500655{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600656 if (status ==
657 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
658 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
659 {
660 return DumpCreationProgress::DUMP_CREATE_FAILED;
661 }
662 if (status ==
663 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
664 {
665 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
666 }
667 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
668}
669
670inline DumpCreationProgress
671 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
672{
673 for (const auto& [key, val] : values)
674 {
675 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700676 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600677 const std::string* value = std::get_if<std::string>(&val);
678 if (value == nullptr)
679 {
680 BMCWEB_LOG_ERROR << "Status property value is null";
681 return DumpCreationProgress::DUMP_CREATE_FAILED;
682 }
683 return mapDbusStatusToDumpProgress(*value);
684 }
685 }
686 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
687}
688
689inline std::string getDumpEntryPath(const std::string& dumpPath)
690{
691 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
692 {
693 return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
694 }
695 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
696 {
697 return "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
698 }
699 return "";
700}
701
702inline void createDumpTaskCallback(
703 task::Payload&& payload,
704 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
705 const sdbusplus::message::object_path& createdObjPath)
706{
707 const std::string dumpPath = createdObjPath.parent_path().str;
708 const std::string dumpId = createdObjPath.filename();
709
710 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
711
712 if (dumpEntryPath.empty())
713 {
714 BMCWEB_LOG_ERROR << "Invalid dump type received";
715 messages::internalError(asyncResp->res);
716 return;
717 }
718
719 crow::connections::systemBus->async_method_call(
720 [asyncResp, payload, createdObjPath,
721 dumpEntryPath{std::move(dumpEntryPath)},
722 dumpId](const boost::system::error_code ec,
723 const std::string& introspectXml) {
724 if (ec)
725 {
726 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
727 << ec.message();
728 messages::internalError(asyncResp->res);
729 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700730 }
731
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600732 // Check if the created dump object has implemented Progress
733 // interface to track dump completion. If yes, fetch the "Status"
734 // property of the interface, modify the task state accordingly.
735 // Else, return task completed.
736 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700737
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600738 doc.Parse(introspectXml.data(), introspectXml.size());
739 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
740 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700741 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600742 BMCWEB_LOG_ERROR << "XML document failed to parse";
743 messages::internalError(asyncResp->res);
744 return;
745 }
746 tinyxml2::XMLElement* interfaceNode =
747 pRoot->FirstChildElement("interface");
748
749 bool isProgressIntfPresent = false;
750 while (interfaceNode != nullptr)
751 {
752 const char* thisInterfaceName = interfaceNode->Attribute("name");
753 if (thisInterfaceName != nullptr)
754 {
755 if (thisInterfaceName ==
756 std::string_view("xyz.openbmc_project.Common.Progress"))
757 {
758 interfaceNode =
759 interfaceNode->NextSiblingElement("interface");
760 continue;
761 }
762 isProgressIntfPresent = true;
763 break;
764 }
765 interfaceNode = interfaceNode->NextSiblingElement("interface");
766 }
767
768 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
769 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
770 boost::system::error_code err, sdbusplus::message::message& msg,
771 const std::shared_ptr<task::TaskData>& taskData) {
772 if (err)
773 {
774 BMCWEB_LOG_ERROR << createdObjPath.str
775 << ": Error in creating dump";
776 taskData->messages.emplace_back(messages::internalError());
777 taskData->state = "Cancelled";
778 return task::completed;
779 }
780
781 if (isProgressIntfPresent)
782 {
783 dbus::utility::DBusPropertiesMap values;
784 std::string prop;
785 msg.read(prop, values);
786
787 DumpCreationProgress dumpStatus =
788 getDumpCompletionStatus(values);
789 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
790 {
791 BMCWEB_LOG_ERROR << createdObjPath.str
792 << ": Error in creating dump";
793 taskData->state = "Cancelled";
794 return task::completed;
795 }
796
797 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
798 {
799 BMCWEB_LOG_DEBUG << createdObjPath.str
800 << ": Dump creation task is in progress";
801 return !task::completed;
802 }
803 }
804
Ed Tanous002d39b2022-05-31 08:59:27 -0700805 nlohmann::json retMessage = messages::success();
806 taskData->messages.emplace_back(retMessage);
807
808 std::string headerLoc =
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600809 "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700810 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
811
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600812 BMCWEB_LOG_DEBUG << createdObjPath.str
813 << ": Dump creation task completed";
Ed Tanous002d39b2022-05-31 08:59:27 -0700814 taskData->state = "Completed";
815 return task::completed;
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600816 },
817 "type='signal',interface='org.freedesktop.DBus.Properties',"
818 "member='PropertiesChanged',path='" +
819 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500820
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600821 // The task timer is set to max time limit within which the
822 // requested dump will be collected.
823 task->startTimer(std::chrono::minutes(6));
824 task->populateResp(asyncResp->res);
825 task->payload.emplace(payload);
826 },
827 "xyz.openbmc_project.Dump.Manager", createdObjPath,
828 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500829}
830
zhanghch058d1b46d2021-04-01 11:18:24 +0800831inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
832 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500833{
Claire Weinanfdd26902022-03-01 14:18:25 -0800834 std::string dumpPath = getDumpEntriesPath(dumpType);
835 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500836 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500837 messages::internalError(asyncResp->res);
838 return;
839 }
840
841 std::optional<std::string> diagnosticDataType;
842 std::optional<std::string> oemDiagnosticDataType;
843
Willy Tu15ed6782021-12-14 11:03:16 -0800844 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500845 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
846 "OEMDiagnosticDataType", oemDiagnosticDataType))
847 {
848 return;
849 }
850
851 if (dumpType == "System")
852 {
853 if (!oemDiagnosticDataType || !diagnosticDataType)
854 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800855 BMCWEB_LOG_ERROR
856 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500857 messages::actionParameterMissing(
858 asyncResp->res, "CollectDiagnosticData",
859 "DiagnosticDataType & OEMDiagnosticDataType");
860 return;
861 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700862 if ((*oemDiagnosticDataType != "System") ||
863 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500864 {
865 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700866 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500867 return;
868 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500869 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500870 }
871 else if (dumpType == "BMC")
872 {
873 if (!diagnosticDataType)
874 {
George Liu0fda0f12021-11-16 10:06:17 +0800875 BMCWEB_LOG_ERROR
876 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500877 messages::actionParameterMissing(
878 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
879 return;
880 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700881 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500882 {
883 BMCWEB_LOG_ERROR
884 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700885 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500886 return;
887 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500888 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
889 }
890 else
891 {
892 BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type";
893 messages::internalError(asyncResp->res);
894 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500895 }
896
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600897 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
898 createDumpParamVec;
899
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500900 crow::connections::systemBus->async_method_call(
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600901 [asyncResp, payload(task::Payload(req)),
902 dumpPath](const boost::system::error_code ec,
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500903 const sdbusplus::message::message& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600904 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700905 if (ec)
906 {
907 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500908 const sd_bus_error* dbusError = msg.get_error();
909 if (dbusError == nullptr)
910 {
911 messages::internalError(asyncResp->res);
912 return;
913 }
914
915 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
916 << " and error msg: " << dbusError->message;
917 if (std::string_view(
918 "xyz.openbmc_project.Common.Error.NotAllowed") ==
919 dbusError->name)
920 {
921 messages::resourceInStandby(asyncResp->res);
922 return;
923 }
924 if (std::string_view(
925 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
926 dbusError->name)
927 {
928 messages::serviceDisabled(asyncResp->res, dumpPath);
929 return;
930 }
931 if (std::string_view(
932 "xyz.openbmc_project.Common.Error.Unavailable") ==
933 dbusError->name)
934 {
935 messages::resourceInUse(asyncResp->res);
936 return;
937 }
938 // Other Dbus errors such as:
939 // xyz.openbmc_project.Common.Error.InvalidArgument &
940 // org.freedesktop.DBus.Error.InvalidArgs are all related to
941 // the dbus call that is made here in the bmcweb
942 // implementation and has nothing to do with the client's
943 // input in the request. Hence, returning internal error
944 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700945 messages::internalError(asyncResp->res);
946 return;
947 }
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600948 BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str;
949 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500950 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500951 "xyz.openbmc_project.Dump.Manager",
952 "/xyz/openbmc_project/dump/" +
953 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600954 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500955}
956
zhanghch058d1b46d2021-04-01 11:18:24 +0800957inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500959{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500960 std::string dumpTypeLowerCopy =
961 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800962
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500963 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800964 [asyncResp, dumpType](
965 const boost::system::error_code ec,
966 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700967 if (ec)
968 {
969 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
970 messages::internalError(asyncResp->res);
971 return;
972 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500973
Ed Tanous002d39b2022-05-31 08:59:27 -0700974 for (const std::string& path : subTreePaths)
975 {
976 sdbusplus::message::object_path objPath(path);
977 std::string logID = objPath.filename();
978 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500979 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700980 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500981 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700982 deleteDumpEntry(asyncResp, logID, dumpType);
983 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500984 },
985 "xyz.openbmc_project.ObjectMapper",
986 "/xyz/openbmc_project/object_mapper",
987 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500988 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
989 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
990 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500991}
992
Ed Tanousb9d36b42022-02-26 21:42:46 -0800993inline static void
994 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
995 std::string& filename, std::string& timestamp,
996 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700997{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200998 const std::string* filenamePtr = nullptr;
999 const std::string* timestampPtr = nullptr;
1000 const std::string* logfilePtr = nullptr;
1001
1002 const bool success = sdbusplus::unpackPropertiesNoThrow(
1003 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1004 "Filename", filenamePtr, "Log", logfilePtr);
1005
1006 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001007 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001008 return;
1009 }
1010
1011 if (filenamePtr != nullptr)
1012 {
1013 filename = *filenamePtr;
1014 }
1015
1016 if (timestampPtr != nullptr)
1017 {
1018 timestamp = *timestampPtr;
1019 }
1020
1021 if (logfilePtr != nullptr)
1022 {
1023 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001024 }
1025}
1026
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001027constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001028inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001029{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001030 /**
1031 * Functions triggers appropriate requests on DBus
1032 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001033 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001034 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001035 .methods(boost::beast::http::verb::get)(
1036 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001037 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1038 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001039 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001040 {
1041 return;
1042 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001043 if (systemName != "system")
1044 {
1045 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1046 systemName);
1047 return;
1048 }
1049
Ed Tanous002d39b2022-05-31 08:59:27 -07001050 // Collections don't include the static data added by SubRoute
1051 // because it has a duplicate entry for members
1052 asyncResp->res.jsonValue["@odata.type"] =
1053 "#LogServiceCollection.LogServiceCollection";
1054 asyncResp->res.jsonValue["@odata.id"] =
1055 "/redfish/v1/Systems/system/LogServices";
1056 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1057 asyncResp->res.jsonValue["Description"] =
1058 "Collection of LogServices for this Computer System";
1059 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1060 logServiceArray = nlohmann::json::array();
1061 nlohmann::json::object_t eventLog;
1062 eventLog["@odata.id"] =
1063 "/redfish/v1/Systems/system/LogServices/EventLog";
1064 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001065#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001066 nlohmann::json::object_t dumpLog;
1067 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
1068 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -06001069#endif
1070
Jason M. Billsd53dd412019-02-12 17:16:22 -08001071#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001072 nlohmann::json::object_t crashdump;
1073 crashdump["@odata.id"] =
1074 "/redfish/v1/Systems/system/LogServices/Crashdump";
1075 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -08001076#endif
Spencer Kub7028eb2021-10-26 15:27:35 +08001077
1078#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -07001079 nlohmann::json::object_t hostlogger;
1080 hostlogger["@odata.id"] =
1081 "/redfish/v1/Systems/system/LogServices/HostLogger";
1082 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +08001083#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07001084 asyncResp->res.jsonValue["Members@odata.count"] =
1085 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001086
Ed Tanous002d39b2022-05-31 08:59:27 -07001087 crow::connections::systemBus->async_method_call(
1088 [asyncResp](const boost::system::error_code ec,
1089 const dbus::utility::MapperGetSubTreePathsResponse&
1090 subtreePath) {
1091 if (ec)
1092 {
1093 BMCWEB_LOG_ERROR << ec;
1094 return;
1095 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001096
Ed Tanous002d39b2022-05-31 08:59:27 -07001097 for (const auto& pathStr : subtreePath)
1098 {
1099 if (pathStr.find("PostCode") != std::string::npos)
1100 {
1101 nlohmann::json& logServiceArrayLocal =
1102 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001103 nlohmann::json::object_t member;
1104 member["@odata.id"] =
1105 "/redfish/v1/Systems/system/LogServices/PostCodes";
1106
1107 logServiceArrayLocal.push_back(std::move(member));
1108
Ed Tanous002d39b2022-05-31 08:59:27 -07001109 asyncResp->res.jsonValue["Members@odata.count"] =
1110 logServiceArrayLocal.size();
1111 return;
1112 }
1113 }
1114 },
1115 "xyz.openbmc_project.ObjectMapper",
1116 "/xyz/openbmc_project/object_mapper",
1117 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
1118 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -07001119 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001120}
1121
1122inline void requestRoutesEventLogService(App& app)
1123{
Ed Tanous22d268c2022-05-19 09:39:07 -07001124 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001125 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001126 .methods(boost::beast::http::verb::get)(
1127 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001128 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1129 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001130 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001131 {
1132 return;
1133 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001134 if (systemName != "system")
1135 {
1136 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1137 systemName);
1138 return;
1139 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001140 asyncResp->res.jsonValue["@odata.id"] =
1141 "/redfish/v1/Systems/system/LogServices/EventLog";
1142 asyncResp->res.jsonValue["@odata.type"] =
1143 "#LogService.v1_1_0.LogService";
1144 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1145 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1146 asyncResp->res.jsonValue["Id"] = "EventLog";
1147 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301148
Ed Tanous002d39b2022-05-31 08:59:27 -07001149 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001150 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301151
Ed Tanous002d39b2022-05-31 08:59:27 -07001152 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1153 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1154 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301155
Ed Tanous002d39b2022-05-31 08:59:27 -07001156 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1157 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1158 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001159
Ed Tanous002d39b2022-05-31 08:59:27 -07001160 {"target",
1161 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001162 });
1163}
1164
1165inline void requestRoutesJournalEventLogClear(App& app)
1166{
Jason M. Bills4978b632022-02-22 14:17:43 -08001167 BMCWEB_ROUTE(
1168 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001169 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001170 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001171 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001172 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001173 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1174 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001175 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001176 {
1177 return;
1178 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001179 if (systemName != "system")
1180 {
1181 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1182 systemName);
1183 return;
1184 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001185 // Clear the EventLog by deleting the log files
1186 std::vector<std::filesystem::path> redfishLogFiles;
1187 if (getRedfishLogFiles(redfishLogFiles))
1188 {
1189 for (const std::filesystem::path& file : redfishLogFiles)
1190 {
1191 std::error_code ec;
1192 std::filesystem::remove(file, ec);
1193 }
1194 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001195
Ed Tanous002d39b2022-05-31 08:59:27 -07001196 // Reload rsyslog so it knows to start new log files
1197 crow::connections::systemBus->async_method_call(
1198 [asyncResp](const boost::system::error_code ec) {
1199 if (ec)
1200 {
1201 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1202 messages::internalError(asyncResp->res);
1203 return;
1204 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001205
Ed Tanous002d39b2022-05-31 08:59:27 -07001206 messages::success(asyncResp->res);
1207 },
1208 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1209 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1210 "replace");
1211 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001212}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001213
Jason M. Billsac992cd2022-06-24 13:31:46 -07001214enum class LogParseError
1215{
1216 success,
1217 parseFailed,
1218 messageIdNotInRegistry,
1219};
1220
1221static LogParseError
1222 fillEventLogEntryJson(const std::string& logEntryID,
1223 const std::string& logEntry,
1224 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001225{
Jason M. Bills95820182019-04-22 16:25:34 -07001226 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001227 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001228 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001229 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001230 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001231 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001232 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001233 std::string timestamp = logEntry.substr(0, space);
1234 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001235 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001236 if (entryStart == std::string::npos)
1237 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001238 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001239 }
1240 std::string_view entry(logEntry);
1241 entry.remove_prefix(entryStart);
1242 // Use split to separate the entry into its fields
1243 std::vector<std::string> logEntryFields;
1244 boost::split(logEntryFields, entry, boost::is_any_of(","),
1245 boost::token_compress_on);
1246 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001247 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001248 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001249 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001250 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001251 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001252
Jason M. Bills4851d452019-03-28 11:27:48 -07001253 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001254 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001255
Sui Chen54417b02022-03-24 14:59:52 -07001256 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001257 {
Sui Chen54417b02022-03-24 14:59:52 -07001258 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001259 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001260 }
1261
Sui Chen54417b02022-03-24 14:59:52 -07001262 std::string msg = message->message;
1263
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001264 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001265 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001266 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001267 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001268 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001269 // If the first string is empty, assume there are no MessageArgs
1270 std::size_t messageArgsSize = 0;
1271 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001272 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001273 messageArgsSize = logEntryFields.size() - 1;
1274 }
1275
Ed Tanous23a21a12020-07-25 04:45:05 +00001276 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001277
1278 // Fill the MessageArgs into the Message
1279 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001280 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001281 {
1282 std::string argStr = "%" + std::to_string(++i);
1283 size_t argPos = msg.find(argStr);
1284 if (argPos != std::string::npos)
1285 {
1286 msg.replace(argPos, argStr.length(), messageArg);
1287 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001288 }
1289 }
1290
Jason M. Bills95820182019-04-22 16:25:34 -07001291 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1292 // format which matches the Redfish format except for the fractional seconds
1293 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001294 std::size_t dot = timestamp.find_first_of('.');
1295 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001296 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001297 {
Jason M. Bills95820182019-04-22 16:25:34 -07001298 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001299 }
1300
1301 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001302 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001303 logEntryJson["@odata.id"] =
1304 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1305 logEntryJson["Name"] = "System Event Log Entry";
1306 logEntryJson["Id"] = logEntryID;
1307 logEntryJson["Message"] = std::move(msg);
1308 logEntryJson["MessageId"] = std::move(messageID);
1309 logEntryJson["MessageArgs"] = messageArgs;
1310 logEntryJson["EntryType"] = "Event";
1311 logEntryJson["Severity"] = message->messageSeverity;
1312 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001313 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001314}
1315
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001316inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001317{
Ed Tanous22d268c2022-05-19 09:39:07 -07001318 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001319 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001320 .methods(boost::beast::http::verb::get)(
1321 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001322 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1323 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001324 query_param::QueryCapabilities capabilities = {
1325 .canDelegateTop = true,
1326 .canDelegateSkip = true,
1327 };
1328 query_param::Query delegatedQuery;
1329 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001330 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001331 {
1332 return;
1333 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001334 if (systemName != "system")
1335 {
1336 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1337 systemName);
1338 return;
1339 }
1340
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001341 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001342 size_t skip = delegatedQuery.skip.value_or(0);
1343
Ed Tanous002d39b2022-05-31 08:59:27 -07001344 // Collections don't include the static data added by SubRoute
1345 // because it has a duplicate entry for members
1346 asyncResp->res.jsonValue["@odata.type"] =
1347 "#LogEntryCollection.LogEntryCollection";
1348 asyncResp->res.jsonValue["@odata.id"] =
1349 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1350 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1351 asyncResp->res.jsonValue["Description"] =
1352 "Collection of System Event Log Entries";
1353
1354 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1355 logEntryArray = nlohmann::json::array();
1356 // Go through the log files and create a unique ID for each
1357 // entry
1358 std::vector<std::filesystem::path> redfishLogFiles;
1359 getRedfishLogFiles(redfishLogFiles);
1360 uint64_t entryCount = 0;
1361 std::string logEntry;
1362
1363 // Oldest logs are in the last file, so start there and loop
1364 // backwards
1365 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1366 it++)
1367 {
1368 std::ifstream logStream(*it);
1369 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001370 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001371 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001372 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001373
Ed Tanous002d39b2022-05-31 08:59:27 -07001374 // Reset the unique ID on the first entry
1375 bool firstEntry = true;
1376 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001377 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001378 std::string idStr;
1379 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001380 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001381 continue;
1382 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001383 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001384
Jason M. Billsde703c52022-06-23 14:19:04 -07001385 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001386 LogParseError status =
1387 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1388 if (status == LogParseError::messageIdNotInRegistry)
1389 {
1390 continue;
1391 }
1392 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001393 {
1394 messages::internalError(asyncResp->res);
1395 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001396 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001397
Jason M. Billsde703c52022-06-23 14:19:04 -07001398 entryCount++;
1399 // Handle paging using skip (number of entries to skip from the
1400 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001401 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001402 {
1403 continue;
1404 }
1405
1406 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001407 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001408 }
1409 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001410 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001411 {
1412 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1413 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001414 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001415 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001416 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001417}
Chicago Duan336e96c2019-07-15 14:22:08 +08001418
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001419inline void requestRoutesJournalEventLogEntry(App& app)
1420{
1421 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001422 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001423 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001424 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001425 [&app](const crow::Request& req,
1426 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001427 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001428 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001429 {
1430 return;
1431 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001432
1433 if (systemName != "system")
1434 {
1435 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1436 systemName);
1437 return;
1438 }
1439
Ed Tanous002d39b2022-05-31 08:59:27 -07001440 const std::string& targetID = param;
1441
1442 // Go through the log files and check the unique ID for each
1443 // entry to find the target entry
1444 std::vector<std::filesystem::path> redfishLogFiles;
1445 getRedfishLogFiles(redfishLogFiles);
1446 std::string logEntry;
1447
1448 // Oldest logs are in the last file, so start there and loop
1449 // backwards
1450 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1451 it++)
1452 {
1453 std::ifstream logStream(*it);
1454 if (!logStream.is_open())
1455 {
1456 continue;
1457 }
1458
1459 // Reset the unique ID on the first entry
1460 bool firstEntry = true;
1461 while (std::getline(logStream, logEntry))
1462 {
1463 std::string idStr;
1464 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001465 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001466 continue;
1467 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001468 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001469
1470 if (idStr == targetID)
1471 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001472 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001473 LogParseError status =
1474 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1475 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001476 {
1477 messages::internalError(asyncResp->res);
1478 return;
1479 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001480 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001481 return;
1482 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001483 }
1484 }
1485 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001486 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07001487 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001488}
1489
1490inline void requestRoutesDBusEventLogEntryCollection(App& app)
1491{
Ed Tanous22d268c2022-05-19 09:39:07 -07001492 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001493 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001494 .methods(boost::beast::http::verb::get)(
1495 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001496 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1497 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001498 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001499 {
1500 return;
1501 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001502 if (systemName != "system")
1503 {
1504 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1505 systemName);
1506 return;
1507 }
1508
Ed Tanous002d39b2022-05-31 08:59:27 -07001509 // Collections don't include the static data added by SubRoute
1510 // because it has a duplicate entry for members
1511 asyncResp->res.jsonValue["@odata.type"] =
1512 "#LogEntryCollection.LogEntryCollection";
1513 asyncResp->res.jsonValue["@odata.id"] =
1514 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1515 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1516 asyncResp->res.jsonValue["Description"] =
1517 "Collection of System Event Log Entries";
1518
1519 // DBus implementation of EventLog/Entries
1520 // Make call to Logging Service to find all log entry objects
1521 crow::connections::systemBus->async_method_call(
1522 [asyncResp](const boost::system::error_code ec,
1523 const dbus::utility::ManagedObjectType& resp) {
1524 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001525 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001526 // TODO Handle for specific error code
1527 BMCWEB_LOG_ERROR
1528 << "getLogEntriesIfaceData resp_handler got error " << ec;
1529 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001530 return;
1531 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001532 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1533 entriesArray = nlohmann::json::array();
1534 for (const auto& objectPath : resp)
1535 {
1536 const uint32_t* id = nullptr;
1537 const uint64_t* timestamp = nullptr;
1538 const uint64_t* updateTimestamp = nullptr;
1539 const std::string* severity = nullptr;
1540 const std::string* message = nullptr;
1541 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001542 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001543 bool resolved = false;
1544 for (const auto& interfaceMap : objectPath.second)
1545 {
1546 if (interfaceMap.first ==
1547 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001548 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001549 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001550 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001551 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001552 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001553 id = std::get_if<uint32_t>(&propertyMap.second);
1554 }
1555 else if (propertyMap.first == "Timestamp")
1556 {
1557 timestamp =
1558 std::get_if<uint64_t>(&propertyMap.second);
1559 }
1560 else if (propertyMap.first == "UpdateTimestamp")
1561 {
1562 updateTimestamp =
1563 std::get_if<uint64_t>(&propertyMap.second);
1564 }
1565 else if (propertyMap.first == "Severity")
1566 {
1567 severity = std::get_if<std::string>(
1568 &propertyMap.second);
1569 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001570 else if (propertyMap.first == "Resolution")
1571 {
1572 resolution = std::get_if<std::string>(
1573 &propertyMap.second);
1574 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001575 else if (propertyMap.first == "Message")
1576 {
1577 message = std::get_if<std::string>(
1578 &propertyMap.second);
1579 }
1580 else if (propertyMap.first == "Resolved")
1581 {
1582 const bool* resolveptr =
1583 std::get_if<bool>(&propertyMap.second);
1584 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001585 {
1586 messages::internalError(asyncResp->res);
1587 return;
1588 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001589 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001590 }
1591 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001592 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001594 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001595 messages::internalError(asyncResp->res);
1596 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001597 }
1598 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001599 else if (interfaceMap.first ==
1600 "xyz.openbmc_project.Common.FilePath")
1601 {
1602 for (const auto& propertyMap : interfaceMap.second)
1603 {
1604 if (propertyMap.first == "Path")
1605 {
1606 filePath = std::get_if<std::string>(
1607 &propertyMap.second);
1608 }
1609 }
1610 }
1611 }
1612 // Object path without the
1613 // xyz.openbmc_project.Logging.Entry interface, ignore
1614 // and continue.
1615 if (id == nullptr || message == nullptr ||
1616 severity == nullptr || timestamp == nullptr ||
1617 updateTimestamp == nullptr)
1618 {
1619 continue;
1620 }
1621 entriesArray.push_back({});
1622 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001623 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001624 thisEntry["@odata.id"] =
1625 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1626 std::to_string(*id);
1627 thisEntry["Name"] = "System Event Log Entry";
1628 thisEntry["Id"] = std::to_string(*id);
1629 thisEntry["Message"] = *message;
1630 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001631 if ((resolution != nullptr) && (!(*resolution).empty()))
1632 {
1633 thisEntry["Resolution"] = *resolution;
1634 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001635 thisEntry["EntryType"] = "Event";
1636 thisEntry["Severity"] =
1637 translateSeverityDbusToRedfish(*severity);
1638 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001639 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001640 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001641 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001642 if (filePath != nullptr)
1643 {
1644 thisEntry["AdditionalDataURI"] =
1645 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1646 std::to_string(*id) + "/attachment";
1647 }
1648 }
1649 std::sort(
1650 entriesArray.begin(), entriesArray.end(),
1651 [](const nlohmann::json& left, const nlohmann::json& right) {
1652 return (left["Id"] <= right["Id"]);
1653 });
1654 asyncResp->res.jsonValue["Members@odata.count"] =
1655 entriesArray.size();
1656 },
1657 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1658 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001659 });
1660}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001661
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001662inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001663{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001664 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001665 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001666 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001667 .methods(boost::beast::http::verb::get)(
1668 [&app](const crow::Request& req,
1669 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001670 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001671 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001672 {
1673 return;
1674 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001675 if (systemName != "system")
1676 {
1677 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1678 systemName);
1679 return;
1680 }
1681
Ed Tanous002d39b2022-05-31 08:59:27 -07001682 std::string entryID = param;
1683 dbus::utility::escapePathForDbus(entryID);
1684
1685 // DBus implementation of EventLog/Entries
1686 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001687 sdbusplus::asio::getAllProperties(
1688 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1689 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001690 [asyncResp, entryID](const boost::system::error_code ec,
1691 const dbus::utility::DBusPropertiesMap& resp) {
1692 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001693 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001694 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1695 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001696 return;
1697 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001698 if (ec)
1699 {
1700 BMCWEB_LOG_ERROR
1701 << "EventLogEntry (DBus) resp_handler got error " << ec;
1702 messages::internalError(asyncResp->res);
1703 return;
1704 }
1705 const uint32_t* id = nullptr;
1706 const uint64_t* timestamp = nullptr;
1707 const uint64_t* updateTimestamp = nullptr;
1708 const std::string* severity = nullptr;
1709 const std::string* message = nullptr;
1710 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001711 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001712 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001713
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001714 const bool success = sdbusplus::unpackPropertiesNoThrow(
1715 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1716 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001717 severity, "Message", message, "Resolved", resolved,
1718 "Resolution", resolution, "Path", filePath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001719
1720 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001721 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001722 messages::internalError(asyncResp->res);
1723 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001724 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001725
Ed Tanous002d39b2022-05-31 08:59:27 -07001726 if (id == nullptr || message == nullptr || severity == nullptr ||
1727 timestamp == nullptr || updateTimestamp == nullptr)
1728 {
1729 messages::internalError(asyncResp->res);
1730 return;
1731 }
1732 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001733 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001734 asyncResp->res.jsonValue["@odata.id"] =
1735 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1736 std::to_string(*id);
1737 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1738 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1739 asyncResp->res.jsonValue["Message"] = *message;
1740 asyncResp->res.jsonValue["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001741 if ((resolution != nullptr) && (!(*resolution).empty()))
1742 {
1743 asyncResp->res.jsonValue["Resolution"] = *resolution;
1744 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001745 asyncResp->res.jsonValue["EntryType"] = "Event";
1746 asyncResp->res.jsonValue["Severity"] =
1747 translateSeverityDbusToRedfish(*severity);
1748 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001749 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001750 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001751 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001752 if (filePath != nullptr)
1753 {
1754 asyncResp->res.jsonValue["AdditionalDataURI"] =
1755 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1756 std::to_string(*id) + "/attachment";
1757 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001758 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001759 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001760
1761 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001762 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001763 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001764 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001765 [&app](const crow::Request& req,
1766 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001767 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001768 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001769 {
1770 return;
1771 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001772 if (systemName != "system")
1773 {
1774 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1775 systemName);
1776 return;
1777 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001778 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001779
Ed Tanous002d39b2022-05-31 08:59:27 -07001780 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1781 resolved))
1782 {
1783 return;
1784 }
1785 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001786
Ed Tanous002d39b2022-05-31 08:59:27 -07001787 crow::connections::systemBus->async_method_call(
1788 [asyncResp, entryId](const boost::system::error_code ec) {
1789 if (ec)
1790 {
1791 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1792 messages::internalError(asyncResp->res);
1793 return;
1794 }
1795 },
1796 "xyz.openbmc_project.Logging",
1797 "/xyz/openbmc_project/logging/entry/" + entryId,
1798 "org.freedesktop.DBus.Properties", "Set",
1799 "xyz.openbmc_project.Logging.Entry", "Resolved",
1800 dbus::utility::DbusVariantType(*resolved));
1801 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001802
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001803 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001804 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001805 .privileges(redfish::privileges::deleteLogEntry)
1806
Ed Tanous002d39b2022-05-31 08:59:27 -07001807 .methods(boost::beast::http::verb::delete_)(
1808 [&app](const crow::Request& req,
1809 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001810 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001811 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001812 {
1813 return;
1814 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001815 if (systemName != "system")
1816 {
1817 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1818 systemName);
1819 return;
1820 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001821 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1822
1823 std::string entryID = param;
1824
1825 dbus::utility::escapePathForDbus(entryID);
1826
1827 // Process response from Logging service.
1828 auto respHandler =
1829 [asyncResp, entryID](const boost::system::error_code ec) {
1830 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1831 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001832 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001833 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001834 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001835 messages::resourceNotFound(asyncResp->res, "LogEntry",
1836 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001837 return;
1838 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001839 // TODO Handle for specific error code
1840 BMCWEB_LOG_ERROR
1841 << "EventLogEntry (DBus) doDelete respHandler got error "
1842 << ec;
1843 asyncResp->res.result(
1844 boost::beast::http::status::internal_server_error);
1845 return;
1846 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001847
Ed Tanous002d39b2022-05-31 08:59:27 -07001848 asyncResp->res.result(boost::beast::http::status::ok);
1849 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001850
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 // Make call to Logging service to request Delete Log
1852 crow::connections::systemBus->async_method_call(
1853 respHandler, "xyz.openbmc_project.Logging",
1854 "/xyz/openbmc_project/logging/entry/" + entryID,
1855 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001856 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001857}
1858
1859inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001860{
George Liu0fda0f12021-11-16 10:06:17 +08001861 BMCWEB_ROUTE(
1862 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001863 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001864 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001865 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001866 [&app](const crow::Request& req,
1867 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001868 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001869 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001870 {
1871 return;
1872 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001873 if (http_helpers::isContentTypeAllowed(
1874 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001875 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001876 {
1877 asyncResp->res.result(boost::beast::http::status::bad_request);
1878 return;
1879 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001880 if (systemName != "system")
1881 {
1882 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1883 systemName);
1884 return;
1885 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001886
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 std::string entryID = param;
1888 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001889
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 crow::connections::systemBus->async_method_call(
1891 [asyncResp, entryID](const boost::system::error_code ec,
1892 const sdbusplus::message::unix_fd& unixfd) {
1893 if (ec.value() == EBADR)
1894 {
1895 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1896 entryID);
1897 return;
1898 }
1899 if (ec)
1900 {
1901 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1902 messages::internalError(asyncResp->res);
1903 return;
1904 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001905
Ed Tanous002d39b2022-05-31 08:59:27 -07001906 int fd = -1;
1907 fd = dup(unixfd);
1908 if (fd == -1)
1909 {
1910 messages::internalError(asyncResp->res);
1911 return;
1912 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001913
Ed Tanous002d39b2022-05-31 08:59:27 -07001914 long long int size = lseek(fd, 0, SEEK_END);
1915 if (size == -1)
1916 {
1917 messages::internalError(asyncResp->res);
1918 return;
1919 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001920
Ed Tanous002d39b2022-05-31 08:59:27 -07001921 // Arbitrary max size of 64kb
1922 constexpr int maxFileSize = 65536;
1923 if (size > maxFileSize)
1924 {
1925 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1926 << maxFileSize;
1927 messages::internalError(asyncResp->res);
1928 return;
1929 }
1930 std::vector<char> data(static_cast<size_t>(size));
1931 long long int rc = lseek(fd, 0, SEEK_SET);
1932 if (rc == -1)
1933 {
1934 messages::internalError(asyncResp->res);
1935 return;
1936 }
1937 rc = read(fd, data.data(), data.size());
1938 if ((rc == -1) || (rc != size))
1939 {
1940 messages::internalError(asyncResp->res);
1941 return;
1942 }
1943 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001944
Ed Tanous002d39b2022-05-31 08:59:27 -07001945 std::string_view strData(data.data(), data.size());
1946 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001947
Ed Tanousd9f6c622022-03-17 09:12:17 -07001948 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001949 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001950 asyncResp->res.addHeader(
1951 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001952 asyncResp->res.body() = std::move(output);
1953 },
1954 "xyz.openbmc_project.Logging",
1955 "/xyz/openbmc_project/logging/entry/" + entryID,
1956 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1957 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001958}
1959
Spencer Kub7028eb2021-10-26 15:27:35 +08001960constexpr const char* hostLoggerFolderPath = "/var/log/console";
1961
1962inline bool
1963 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1964 std::vector<std::filesystem::path>& hostLoggerFiles)
1965{
1966 std::error_code ec;
1967 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1968 if (ec)
1969 {
1970 BMCWEB_LOG_ERROR << ec.message();
1971 return false;
1972 }
1973 for (const std::filesystem::directory_entry& it : logPath)
1974 {
1975 std::string filename = it.path().filename();
1976 // Prefix of each log files is "log". Find the file and save the
1977 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07001978 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08001979 {
1980 hostLoggerFiles.emplace_back(it.path());
1981 }
1982 }
1983 // As the log files rotate, they are appended with a ".#" that is higher for
1984 // the older logs. Since we start from oldest logs, sort the name in
1985 // descending order.
1986 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1987 AlphanumLess<std::string>());
1988
1989 return true;
1990}
1991
Ed Tanous02cad962022-06-30 16:50:15 -07001992inline bool getHostLoggerEntries(
1993 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
1994 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001995{
1996 GzFileReader logFile;
1997
1998 // Go though all log files and expose host logs.
1999 for (const std::filesystem::path& it : hostLoggerFiles)
2000 {
2001 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2002 {
2003 BMCWEB_LOG_ERROR << "fail to expose host logs";
2004 return false;
2005 }
2006 }
2007 // Get lastMessage from constructor by getter
2008 std::string lastMessage = logFile.getLastMessage();
2009 if (!lastMessage.empty())
2010 {
2011 logCount++;
2012 if (logCount > skip && logCount <= (skip + top))
2013 {
2014 logEntries.push_back(lastMessage);
2015 }
2016 }
2017 return true;
2018}
2019
2020inline void fillHostLoggerEntryJson(const std::string& logEntryID,
2021 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002022 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002023{
2024 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002025 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002026 logEntryJson["@odata.id"] =
2027 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
2028 logEntryID;
2029 logEntryJson["Name"] = "Host Logger Entry";
2030 logEntryJson["Id"] = logEntryID;
2031 logEntryJson["Message"] = msg;
2032 logEntryJson["EntryType"] = "Oem";
2033 logEntryJson["Severity"] = "OK";
2034 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002035}
2036
2037inline void requestRoutesSystemHostLogger(App& app)
2038{
Ed Tanous22d268c2022-05-19 09:39:07 -07002039 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002040 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002041 .methods(boost::beast::http::verb::get)(
2042 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002043 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2044 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002045 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002046 {
2047 return;
2048 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002049 if (systemName != "system")
2050 {
2051 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2052 systemName);
2053 return;
2054 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002055 asyncResp->res.jsonValue["@odata.id"] =
2056 "/redfish/v1/Systems/system/LogServices/HostLogger";
2057 asyncResp->res.jsonValue["@odata.type"] =
2058 "#LogService.v1_1_0.LogService";
2059 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2060 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2061 asyncResp->res.jsonValue["Id"] = "HostLogger";
2062 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2063 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2064 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002065}
2066
2067inline void requestRoutesSystemHostLoggerCollection(App& app)
2068{
2069 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002070 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002071 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002072 .methods(boost::beast::http::verb::get)(
2073 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002074 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2075 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002076 query_param::QueryCapabilities capabilities = {
2077 .canDelegateTop = true,
2078 .canDelegateSkip = true,
2079 };
2080 query_param::Query delegatedQuery;
2081 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002082 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002083 {
2084 return;
2085 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002086 if (systemName != "system")
2087 {
2088 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2089 systemName);
2090 return;
2091 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002092 asyncResp->res.jsonValue["@odata.id"] =
2093 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2094 asyncResp->res.jsonValue["@odata.type"] =
2095 "#LogEntryCollection.LogEntryCollection";
2096 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2097 asyncResp->res.jsonValue["Description"] =
2098 "Collection of HostLogger Entries";
2099 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2100 logEntryArray = nlohmann::json::array();
2101 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002102
Ed Tanous002d39b2022-05-31 08:59:27 -07002103 std::vector<std::filesystem::path> hostLoggerFiles;
2104 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2105 {
2106 BMCWEB_LOG_ERROR << "fail to get host log file path";
2107 return;
2108 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002109 // If we weren't provided top and skip limits, use the defaults.
2110 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002111 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002112 size_t logCount = 0;
2113 // This vector only store the entries we want to expose that
2114 // control by skip and top.
2115 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002116 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2117 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002118 {
2119 messages::internalError(asyncResp->res);
2120 return;
2121 }
2122 // If vector is empty, that means skip value larger than total
2123 // log count
2124 if (logEntries.empty())
2125 {
2126 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2127 return;
2128 }
2129 if (!logEntries.empty())
2130 {
2131 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002132 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002133 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002134 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2135 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002136 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002137 }
2138
Ed Tanous002d39b2022-05-31 08:59:27 -07002139 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002140 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002141 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002142 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2143 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002144 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002145 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002146 }
George Liu0fda0f12021-11-16 10:06:17 +08002147 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002148}
2149
2150inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2151{
2152 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002153 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002154 .privileges(redfish::privileges::getLogEntry)
2155 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002156 [&app](const crow::Request& req,
2157 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002158 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002159 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002160 {
2161 return;
2162 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002163 if (systemName != "system")
2164 {
2165 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2166 systemName);
2167 return;
2168 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002169 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002170
Ed Tanous002d39b2022-05-31 08:59:27 -07002171 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002172
Ed Tanous002d39b2022-05-31 08:59:27 -07002173 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2174 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002175
Ed Tanous002d39b2022-05-31 08:59:27 -07002176 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002177 if (ec == std::errc::invalid_argument ||
2178 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002179 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002180 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002181 return;
2182 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002183
Ed Tanous002d39b2022-05-31 08:59:27 -07002184 std::vector<std::filesystem::path> hostLoggerFiles;
2185 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2186 {
2187 BMCWEB_LOG_ERROR << "fail to get host log file path";
2188 return;
2189 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002190
Ed Tanous002d39b2022-05-31 08:59:27 -07002191 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002192 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002193 std::vector<std::string> logEntries;
2194 // We can get specific entry by skip and top. For example, if we
2195 // want to get nth entry, we can set skip = n-1 and top = 1 to
2196 // get that entry
2197 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2198 logCount))
2199 {
2200 messages::internalError(asyncResp->res);
2201 return;
2202 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002203
Ed Tanous002d39b2022-05-31 08:59:27 -07002204 if (!logEntries.empty())
2205 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002206 nlohmann::json::object_t hostLogEntry;
2207 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2208 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002209 return;
2210 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002211
Ed Tanous002d39b2022-05-31 08:59:27 -07002212 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002213 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002214 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002215}
2216
Claire Weinanfdd26902022-03-01 14:18:25 -08002217constexpr char const* dumpManagerIface =
2218 "xyz.openbmc_project.Collection.DeleteAll";
Claire Weinandd72e872022-08-15 14:20:06 -07002219inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002220 crow::App& app, const crow::Request& req,
2221 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2222{
2223 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2224 {
2225 return;
2226 }
2227 // Collections don't include the static data added by SubRoute
2228 // because it has a duplicate entry for members
2229 asyncResp->res.jsonValue["@odata.type"] =
2230 "#LogServiceCollection.LogServiceCollection";
2231 asyncResp->res.jsonValue["@odata.id"] =
2232 "/redfish/v1/Managers/bmc/LogServices";
2233 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2234 asyncResp->res.jsonValue["Description"] =
2235 "Collection of LogServices for this Manager";
2236 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2237 logServiceArray = nlohmann::json::array();
2238
2239#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002240 nlohmann::json::object_t journal;
2241 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2242 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002243#endif
2244
2245 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2246
2247#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2248 auto respHandler =
2249 [asyncResp](
2250 const boost::system::error_code ec,
2251 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2252 if (ec)
2253 {
2254 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002255 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002256 << ec;
2257 // Assume that getting an error simply means there are no dump
2258 // LogServices. Return without adding any error response.
2259 return;
2260 }
2261
2262 nlohmann::json& logServiceArrayLocal =
2263 asyncResp->res.jsonValue["Members"];
2264
2265 for (const std::string& path : subTreePaths)
2266 {
2267 if (path == "/xyz/openbmc_project/dump/bmc")
2268 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002269 nlohmann::json::object_t member;
2270 member["@odata.id"] =
2271 "/redfish/v1/Managers/bmc/LogServices/Dump";
2272 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002273 }
2274 else if (path == "/xyz/openbmc_project/dump/faultlog")
2275 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002276 nlohmann::json::object_t member;
2277 member["@odata.id"] =
2278 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2279 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002280 }
2281 }
2282
2283 asyncResp->res.jsonValue["Members@odata.count"] =
2284 logServiceArrayLocal.size();
2285 };
2286
2287 crow::connections::systemBus->async_method_call(
2288 respHandler, "xyz.openbmc_project.ObjectMapper",
2289 "/xyz/openbmc_project/object_mapper",
2290 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2291 "/xyz/openbmc_project/dump", 0,
2292 std::array<const char*, 1>{dumpManagerIface});
2293#endif
2294}
2295
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002296inline void requestRoutesBMCLogServiceCollection(App& app)
2297{
2298 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002299 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002300 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002301 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002302}
Ed Tanous1da66f72018-07-27 16:13:37 -07002303
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002304inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002305{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002306 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002307 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002308 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002309 [&app](const crow::Request& req,
2310 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002311 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002312 {
2313 return;
2314 }
2315 asyncResp->res.jsonValue["@odata.type"] =
2316 "#LogService.v1_1_0.LogService";
2317 asyncResp->res.jsonValue["@odata.id"] =
2318 "/redfish/v1/Managers/bmc/LogServices/Journal";
2319 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2320 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2321 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2322 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302323
Ed Tanous002d39b2022-05-31 08:59:27 -07002324 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002325 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002326 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2327 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2328 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302329
Ed Tanous002d39b2022-05-31 08:59:27 -07002330 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2331 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2332 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002333}
Jason M. Billse1f26342018-07-18 12:12:00 -07002334
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002335static int
2336 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2337 sd_journal* journal,
2338 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002339{
2340 // Get the Log Entry contents
2341 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002342
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002343 std::string message;
2344 std::string_view syslogID;
2345 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2346 if (ret < 0)
2347 {
2348 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2349 << strerror(-ret);
2350 }
2351 if (!syslogID.empty())
2352 {
2353 message += std::string(syslogID) + ": ";
2354 }
2355
Ed Tanous39e77502019-03-04 17:35:53 -08002356 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002357 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002358 if (ret < 0)
2359 {
2360 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2361 return 1;
2362 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002363 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002364
2365 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002366 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002367 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002368 if (ret < 0)
2369 {
2370 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002371 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002372
2373 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002374 std::string entryTimeStr;
2375 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002376 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002377 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002378 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002379
2380 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002381 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002382 bmcJournalLogEntryJson["@odata.id"] =
2383 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2384 bmcJournalLogEntryID;
2385 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2386 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2387 bmcJournalLogEntryJson["Message"] = std::move(message);
2388 bmcJournalLogEntryJson["EntryType"] = "Oem";
2389 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2390 : severity <= 4 ? "Warning"
2391 : "OK";
2392 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2393 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002394 return 0;
2395}
2396
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002397inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002398{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002399 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002400 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002401 .methods(boost::beast::http::verb::get)(
2402 [&app](const crow::Request& req,
2403 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2404 query_param::QueryCapabilities capabilities = {
2405 .canDelegateTop = true,
2406 .canDelegateSkip = true,
2407 };
2408 query_param::Query delegatedQuery;
2409 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002410 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002411 {
2412 return;
2413 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002414
2415 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002416 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002417
Ed Tanous002d39b2022-05-31 08:59:27 -07002418 // Collections don't include the static data added by SubRoute
2419 // because it has a duplicate entry for members
2420 asyncResp->res.jsonValue["@odata.type"] =
2421 "#LogEntryCollection.LogEntryCollection";
2422 asyncResp->res.jsonValue["@odata.id"] =
2423 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2424 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2425 asyncResp->res.jsonValue["Description"] =
2426 "Collection of BMC Journal Entries";
2427 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2428 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002429
Ed Tanous002d39b2022-05-31 08:59:27 -07002430 // Go through the journal and use the timestamp to create a
2431 // unique ID for each entry
2432 sd_journal* journalTmp = nullptr;
2433 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2434 if (ret < 0)
2435 {
2436 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2437 messages::internalError(asyncResp->res);
2438 return;
2439 }
2440 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2441 journalTmp, sd_journal_close);
2442 journalTmp = nullptr;
2443 uint64_t entryCount = 0;
2444 // Reset the unique ID on the first entry
2445 bool firstEntry = true;
2446 SD_JOURNAL_FOREACH(journal.get())
2447 {
2448 entryCount++;
2449 // Handle paging using skip (number of entries to skip from
2450 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002451 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002452 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002453 continue;
2454 }
2455
2456 std::string idStr;
2457 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2458 {
2459 continue;
2460 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002461 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002462
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002463 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002464 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2465 bmcJournalLogEntry) != 0)
2466 {
George Liu0fda0f12021-11-16 10:06:17 +08002467 messages::internalError(asyncResp->res);
2468 return;
2469 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002470 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002471 }
2472 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002473 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002474 {
2475 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2476 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002477 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002478 }
George Liu0fda0f12021-11-16 10:06:17 +08002479 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002480}
Jason M. Billse1f26342018-07-18 12:12:00 -07002481
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002482inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002483{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002484 BMCWEB_ROUTE(app,
2485 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002486 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002487 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002488 [&app](const crow::Request& req,
2489 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2490 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002491 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002492 {
2493 return;
2494 }
2495 // Convert the unique ID back to a timestamp to find the entry
2496 uint64_t ts = 0;
2497 uint64_t index = 0;
2498 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2499 {
2500 return;
2501 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002502
Ed Tanous002d39b2022-05-31 08:59:27 -07002503 sd_journal* journalTmp = nullptr;
2504 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2505 if (ret < 0)
2506 {
2507 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2508 messages::internalError(asyncResp->res);
2509 return;
2510 }
2511 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2512 journalTmp, sd_journal_close);
2513 journalTmp = nullptr;
2514 // Go to the timestamp in the log and move to the entry at the
2515 // index tracking the unique ID
2516 std::string idStr;
2517 bool firstEntry = true;
2518 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2519 if (ret < 0)
2520 {
2521 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2522 << strerror(-ret);
2523 messages::internalError(asyncResp->res);
2524 return;
2525 }
2526 for (uint64_t i = 0; i <= index; i++)
2527 {
2528 sd_journal_next(journal.get());
2529 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2530 {
2531 messages::internalError(asyncResp->res);
2532 return;
2533 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002534 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 }
2536 // Confirm that the entry ID matches what was requested
2537 if (idStr != entryID)
2538 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002539 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002540 return;
2541 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002542
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002543 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002544 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002545 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002546 {
2547 messages::internalError(asyncResp->res);
2548 return;
2549 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002550 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002551 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002552}
2553
Claire Weinanfdd26902022-03-01 14:18:25 -08002554inline void
2555 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2556 const std::string& dumpType)
2557{
2558 std::string dumpPath;
2559 std::string overWritePolicy;
2560 bool collectDiagnosticDataSupported = false;
2561
2562 if (dumpType == "BMC")
2563 {
2564 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2565 overWritePolicy = "WrapsWhenFull";
2566 collectDiagnosticDataSupported = true;
2567 }
2568 else if (dumpType == "FaultLog")
2569 {
2570 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2571 overWritePolicy = "Unknown";
2572 collectDiagnosticDataSupported = false;
2573 }
2574 else if (dumpType == "System")
2575 {
2576 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2577 overWritePolicy = "WrapsWhenFull";
2578 collectDiagnosticDataSupported = true;
2579 }
2580 else
2581 {
2582 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2583 << dumpType;
2584 messages::internalError(asyncResp->res);
2585 return;
2586 }
2587
2588 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2589 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2590 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2591 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2592 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2593 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2594
2595 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002596 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002597 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2598 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2599 redfishDateTimeOffset.second;
2600
2601 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2602 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2603 dumpPath + "/Actions/LogService.ClearLog";
2604
2605 if (collectDiagnosticDataSupported)
2606 {
2607 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2608 ["target"] =
2609 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2610 }
2611}
2612
2613inline void handleLogServicesDumpServiceGet(
2614 crow::App& app, const std::string& dumpType, const crow::Request& req,
2615 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2616{
2617 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2618 {
2619 return;
2620 }
2621 getDumpServiceInfo(asyncResp, dumpType);
2622}
2623
Ed Tanous22d268c2022-05-19 09:39:07 -07002624inline void handleLogServicesDumpServiceComputerSystemGet(
2625 crow::App& app, const crow::Request& req,
2626 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2627 const std::string& chassisId)
2628{
2629 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2630 {
2631 return;
2632 }
2633 if (chassisId != "system")
2634 {
2635 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2636 return;
2637 }
2638 getDumpServiceInfo(asyncResp, "System");
2639}
2640
Claire Weinanfdd26902022-03-01 14:18:25 -08002641inline void handleLogServicesDumpEntriesCollectionGet(
2642 crow::App& app, const std::string& dumpType, const crow::Request& req,
2643 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2644{
2645 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2646 {
2647 return;
2648 }
2649 getDumpEntryCollection(asyncResp, dumpType);
2650}
2651
Ed Tanous22d268c2022-05-19 09:39:07 -07002652inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2653 crow::App& app, const crow::Request& req,
2654 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2655 const std::string& chassisId)
2656{
2657 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2658 {
2659 return;
2660 }
2661 if (chassisId != "system")
2662 {
2663 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2664 return;
2665 }
2666 getDumpEntryCollection(asyncResp, "System");
2667}
2668
Claire Weinanfdd26902022-03-01 14:18:25 -08002669inline void handleLogServicesDumpEntryGet(
2670 crow::App& app, const std::string& dumpType, const crow::Request& req,
2671 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2672 const std::string& dumpId)
2673{
2674 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2675 {
2676 return;
2677 }
2678 getDumpEntryById(asyncResp, dumpId, dumpType);
2679}
Ed Tanous22d268c2022-05-19 09:39:07 -07002680inline void handleLogServicesDumpEntryComputerSystemGet(
2681 crow::App& app, const crow::Request& req,
2682 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2683 const std::string& chassisId, const std::string& dumpId)
2684{
2685 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2686 {
2687 return;
2688 }
2689 if (chassisId != "system")
2690 {
2691 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2692 return;
2693 }
2694 getDumpEntryById(asyncResp, dumpId, "System");
2695}
Claire Weinanfdd26902022-03-01 14:18:25 -08002696
2697inline void handleLogServicesDumpEntryDelete(
2698 crow::App& app, const std::string& dumpType, const crow::Request& req,
2699 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2700 const std::string& dumpId)
2701{
2702 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2703 {
2704 return;
2705 }
2706 deleteDumpEntry(asyncResp, dumpId, dumpType);
2707}
2708
Ed Tanous22d268c2022-05-19 09:39:07 -07002709inline void handleLogServicesDumpEntryComputerSystemDelete(
2710 crow::App& app, const crow::Request& req,
2711 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2712 const std::string& chassisId, const std::string& dumpId)
2713{
2714 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2715 {
2716 return;
2717 }
2718 if (chassisId != "system")
2719 {
2720 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2721 return;
2722 }
2723 deleteDumpEntry(asyncResp, dumpId, "System");
2724}
2725
Claire Weinanfdd26902022-03-01 14:18:25 -08002726inline void handleLogServicesDumpCollectDiagnosticDataPost(
2727 crow::App& app, const std::string& dumpType, const crow::Request& req,
2728 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2729{
2730 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2731 {
2732 return;
2733 }
2734 createDump(asyncResp, req, dumpType);
2735}
2736
Ed Tanous22d268c2022-05-19 09:39:07 -07002737inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2738 crow::App& app, const crow::Request& req,
2739 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2740 const std::string& chassisId)
2741{
2742 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2743 {
2744 return;
2745 }
2746 if (chassisId != "system")
2747 {
2748 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2749 return;
2750 }
2751 createDump(asyncResp, req, "System");
2752}
2753
Claire Weinanfdd26902022-03-01 14:18:25 -08002754inline void handleLogServicesDumpClearLogPost(
2755 crow::App& app, const std::string& dumpType, const crow::Request& req,
2756 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2757{
2758 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2759 {
2760 return;
2761 }
2762 clearDump(asyncResp, dumpType);
2763}
2764
Ed Tanous22d268c2022-05-19 09:39:07 -07002765inline void handleLogServicesDumpClearLogComputerSystemPost(
2766 crow::App& app, const crow::Request& req,
2767 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2768 const std::string& chassisId)
2769{
2770 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2771 {
2772 return;
2773 }
2774 if (chassisId != "system")
2775 {
2776 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2777 return;
2778 }
2779 clearDump(asyncResp, "System");
2780}
2781
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002782inline void requestRoutesBMCDumpService(App& app)
2783{
2784 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002785 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002786 .methods(boost::beast::http::verb::get)(std::bind_front(
2787 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002788}
2789
2790inline void requestRoutesBMCDumpEntryCollection(App& app)
2791{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002792 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002793 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002794 .methods(boost::beast::http::verb::get)(std::bind_front(
2795 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002796}
2797
2798inline void requestRoutesBMCDumpEntry(App& app)
2799{
2800 BMCWEB_ROUTE(app,
2801 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002802 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002803 .methods(boost::beast::http::verb::get)(std::bind_front(
2804 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2805
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002806 BMCWEB_ROUTE(app,
2807 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002808 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002809 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2810 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002811}
2812
2813inline void requestRoutesBMCDumpCreate(App& app)
2814{
George Liu0fda0f12021-11-16 10:06:17 +08002815 BMCWEB_ROUTE(
2816 app,
2817 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002818 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002819 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002820 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2821 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002822}
2823
2824inline void requestRoutesBMCDumpClear(App& app)
2825{
George Liu0fda0f12021-11-16 10:06:17 +08002826 BMCWEB_ROUTE(
2827 app,
2828 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002829 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002830 .methods(boost::beast::http::verb::post)(std::bind_front(
2831 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2832}
2833
2834inline void requestRoutesFaultLogDumpService(App& app)
2835{
2836 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2837 .privileges(redfish::privileges::getLogService)
2838 .methods(boost::beast::http::verb::get)(std::bind_front(
2839 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2840}
2841
2842inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2843{
2844 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2845 .privileges(redfish::privileges::getLogEntryCollection)
2846 .methods(boost::beast::http::verb::get)(
2847 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2848 std::ref(app), "FaultLog"));
2849}
2850
2851inline void requestRoutesFaultLogDumpEntry(App& app)
2852{
2853 BMCWEB_ROUTE(app,
2854 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2855 .privileges(redfish::privileges::getLogEntry)
2856 .methods(boost::beast::http::verb::get)(std::bind_front(
2857 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2858
2859 BMCWEB_ROUTE(app,
2860 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2861 .privileges(redfish::privileges::deleteLogEntry)
2862 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2863 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2864}
2865
2866inline void requestRoutesFaultLogDumpClear(App& app)
2867{
2868 BMCWEB_ROUTE(
2869 app,
2870 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2871 .privileges(redfish::privileges::postLogService)
2872 .methods(boost::beast::http::verb::post)(std::bind_front(
2873 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002874}
2875
2876inline void requestRoutesSystemDumpService(App& app)
2877{
Ed Tanous22d268c2022-05-19 09:39:07 -07002878 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002879 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002880 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002881 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002882}
2883
2884inline void requestRoutesSystemDumpEntryCollection(App& app)
2885{
Ed Tanous22d268c2022-05-19 09:39:07 -07002886 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002887 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002888 .methods(boost::beast::http::verb::get)(std::bind_front(
2889 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2890 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002891}
2892
2893inline void requestRoutesSystemDumpEntry(App& app)
2894{
2895 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002896 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002897 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002898 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002899 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002900
2901 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002902 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002903 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002904 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002905 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002906}
2907
2908inline void requestRoutesSystemDumpCreate(App& app)
2909{
George Liu0fda0f12021-11-16 10:06:17 +08002910 BMCWEB_ROUTE(
2911 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002912 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002913 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002914 .methods(boost::beast::http::verb::post)(std::bind_front(
2915 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2916 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002917}
2918
2919inline void requestRoutesSystemDumpClear(App& app)
2920{
George Liu0fda0f12021-11-16 10:06:17 +08002921 BMCWEB_ROUTE(
2922 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002923 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002924 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002925 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002926 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002927}
2928
2929inline void requestRoutesCrashdumpService(App& app)
2930{
2931 // Note: Deviated from redfish privilege registry for GET & HEAD
2932 // method for security reasons.
2933 /**
2934 * Functions triggers appropriate requests on DBus
2935 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002936 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002937 // This is incorrect, should be:
2938 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002939 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002940 .methods(boost::beast::http::verb::get)(
2941 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002942 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2943 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002944 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002945 {
2946 return;
2947 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002948 if (systemName != "system")
2949 {
2950 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2951 systemName);
2952 return;
2953 }
2954
Ed Tanous002d39b2022-05-31 08:59:27 -07002955 // Copy over the static data to include the entries added by
2956 // SubRoute
2957 asyncResp->res.jsonValue["@odata.id"] =
2958 "/redfish/v1/Systems/system/LogServices/Crashdump";
2959 asyncResp->res.jsonValue["@odata.type"] =
2960 "#LogService.v1_2_0.LogService";
2961 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2962 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2963 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2964 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2965 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302966
Ed Tanous002d39b2022-05-31 08:59:27 -07002967 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002968 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002969 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2970 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2971 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302972
Ed Tanous002d39b2022-05-31 08:59:27 -07002973 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2974 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2975 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2976 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2977 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2978 ["target"] =
2979 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002980 });
2981}
2982
2983void inline requestRoutesCrashdumpClear(App& app)
2984{
George Liu0fda0f12021-11-16 10:06:17 +08002985 BMCWEB_ROUTE(
2986 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002987 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002988 // This is incorrect, should be:
2989 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002990 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002991 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002992 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002993 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2994 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002995 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002996 {
2997 return;
2998 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002999 if (systemName != "system")
3000 {
3001 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3002 systemName);
3003 return;
3004 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003005 crow::connections::systemBus->async_method_call(
3006 [asyncResp](const boost::system::error_code ec,
3007 const std::string&) {
3008 if (ec)
3009 {
3010 messages::internalError(asyncResp->res);
3011 return;
3012 }
3013 messages::success(asyncResp->res);
3014 },
3015 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
3016 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003017}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003018
zhanghch058d1b46d2021-04-01 11:18:24 +08003019static void
3020 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3021 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003022{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003023 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003024 [asyncResp, logID,
3025 &logEntryJson](const boost::system::error_code ec,
3026 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003027 if (ec)
3028 {
3029 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3030 if (ec.value() ==
3031 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003032 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003033 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003034 }
3035 else
3036 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003037 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003038 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003039 return;
3040 }
3041
3042 std::string timestamp{};
3043 std::string filename{};
3044 std::string logfile{};
3045 parseCrashdumpParameters(params, filename, timestamp, logfile);
3046
3047 if (filename.empty() || timestamp.empty())
3048 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003049 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003050 return;
3051 }
3052
3053 std::string crashdumpURI =
3054 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3055 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003056 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003057 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003058 logEntry["@odata.id"] =
3059 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
3060 logEntry["Name"] = "CPU Crashdump";
3061 logEntry["Id"] = logID;
3062 logEntry["EntryType"] = "Oem";
3063 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3064 logEntry["DiagnosticDataType"] = "OEM";
3065 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3066 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003067
3068 // If logEntryJson references an array of LogEntry resources
3069 // ('Members' list), then push this as a new entry, otherwise set it
3070 // directly
3071 if (logEntryJson.is_array())
3072 {
3073 logEntryJson.push_back(logEntry);
3074 asyncResp->res.jsonValue["Members@odata.count"] =
3075 logEntryJson.size();
3076 }
3077 else
3078 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003079 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003080 }
3081 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003082 sdbusplus::asio::getAllProperties(
3083 *crow::connections::systemBus, crashdumpObject,
3084 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3085 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003086}
3087
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003088inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003089{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003090 // Note: Deviated from redfish privilege registry for GET & HEAD
3091 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003092 /**
3093 * Functions triggers appropriate requests on DBus
3094 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003095 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003096 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003097 // This is incorrect, should be.
3098 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003099 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003100 .methods(boost::beast::http::verb::get)(
3101 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003102 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3103 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003104 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003105 {
3106 return;
3107 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003108 if (systemName != "system")
3109 {
3110 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3111 systemName);
3112 return;
3113 }
3114
Ed Tanous002d39b2022-05-31 08:59:27 -07003115 crow::connections::systemBus->async_method_call(
3116 [asyncResp](const boost::system::error_code ec,
3117 const std::vector<std::string>& resp) {
3118 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003119 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003120 if (ec.value() !=
3121 boost::system::errc::no_such_file_or_directory)
3122 {
3123 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3124 << ec.message();
3125 messages::internalError(asyncResp->res);
3126 return;
3127 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003128 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003129 asyncResp->res.jsonValue["@odata.type"] =
3130 "#LogEntryCollection.LogEntryCollection";
3131 asyncResp->res.jsonValue["@odata.id"] =
3132 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3133 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3134 asyncResp->res.jsonValue["Description"] =
3135 "Collection of Crashdump Entries";
3136 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3137 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003138
Ed Tanous002d39b2022-05-31 08:59:27 -07003139 for (const std::string& path : resp)
3140 {
3141 const sdbusplus::message::object_path objPath(path);
3142 // Get the log ID
3143 std::string logID = objPath.filename();
3144 if (logID.empty())
3145 {
3146 continue;
3147 }
3148 // Add the log entry to the array
3149 logCrashdumpEntry(asyncResp, logID,
3150 asyncResp->res.jsonValue["Members"]);
3151 }
3152 },
3153 "xyz.openbmc_project.ObjectMapper",
3154 "/xyz/openbmc_project/object_mapper",
3155 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
3156 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003157 });
3158}
Ed Tanous1da66f72018-07-27 16:13:37 -07003159
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003160inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003161{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003162 // Note: Deviated from redfish privilege registry for GET & HEAD
3163 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003164
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003165 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003166 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003167 // this is incorrect, should be
3168 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003169 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003170 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003171 [&app](const crow::Request& req,
3172 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003173 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003174 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003175 {
3176 return;
3177 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003178 if (systemName != "system")
3179 {
3180 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3181 systemName);
3182 ;
3183 return;
3184 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003185 const std::string& logID = param;
3186 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3187 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003188}
Ed Tanous1da66f72018-07-27 16:13:37 -07003189
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003190inline void requestRoutesCrashdumpFile(App& app)
3191{
3192 // Note: Deviated from redfish privilege registry for GET & HEAD
3193 // method for security reasons.
3194 BMCWEB_ROUTE(
3195 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003196 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003197 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003198 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003199 [](const crow::Request& req,
3200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003201 const std::string& systemName, const std::string& logID,
3202 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003203 // Do not call getRedfishRoute here since the crashdump file is not a
3204 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003205
3206 if (systemName != "system")
3207 {
3208 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3209 systemName);
3210 ;
3211 return;
3212 }
3213
Ed Tanous002d39b2022-05-31 08:59:27 -07003214 auto getStoredLogCallback =
3215 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3216 const boost::system::error_code ec,
3217 const std::vector<
3218 std::pair<std::string, dbus::utility::DbusVariantType>>&
3219 resp) {
3220 if (ec)
3221 {
3222 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3223 messages::internalError(asyncResp->res);
3224 return;
3225 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003226
Ed Tanous002d39b2022-05-31 08:59:27 -07003227 std::string dbusFilename{};
3228 std::string dbusTimestamp{};
3229 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003230
Ed Tanous002d39b2022-05-31 08:59:27 -07003231 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3232 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003233
Ed Tanous002d39b2022-05-31 08:59:27 -07003234 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3235 dbusFilepath.empty())
3236 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003237 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003238 return;
3239 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003240
Ed Tanous002d39b2022-05-31 08:59:27 -07003241 // Verify the file name parameter is correct
3242 if (fileName != dbusFilename)
3243 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003244 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003245 return;
3246 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003247
Ed Tanous002d39b2022-05-31 08:59:27 -07003248 if (!std::filesystem::exists(dbusFilepath))
3249 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003250 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003251 return;
3252 }
3253 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3254 asyncResp->res.body() =
3255 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003256
Ed Tanous002d39b2022-05-31 08:59:27 -07003257 // Configure this to be a file download when accessed
3258 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003259 asyncResp->res.addHeader(
3260 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003261 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003262 sdbusplus::asio::getAllProperties(
3263 *crow::connections::systemBus, crashdumpObject,
3264 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3265 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003266 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003267}
3268
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003269enum class OEMDiagnosticType
3270{
3271 onDemand,
3272 telemetry,
3273 invalid,
3274};
3275
Ed Tanousf7725d72022-03-07 12:46:00 -08003276inline OEMDiagnosticType
3277 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003278{
3279 if (oemDiagStr == "OnDemand")
3280 {
3281 return OEMDiagnosticType::onDemand;
3282 }
3283 if (oemDiagStr == "Telemetry")
3284 {
3285 return OEMDiagnosticType::telemetry;
3286 }
3287
3288 return OEMDiagnosticType::invalid;
3289}
3290
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003291inline void requestRoutesCrashdumpCollect(App& app)
3292{
3293 // Note: Deviated from redfish privilege registry for GET & HEAD
3294 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003295 BMCWEB_ROUTE(
3296 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003297 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003298 // The below is incorrect; Should be ConfigureManager
3299 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003300 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003301 .methods(boost::beast::http::verb::post)(
3302 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003303 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3304 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003305 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003306 {
3307 return;
3308 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003309
3310 if (systemName != "system")
3311 {
3312 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3313 systemName);
3314 ;
3315 return;
3316 }
3317
Ed Tanous002d39b2022-05-31 08:59:27 -07003318 std::string diagnosticDataType;
3319 std::string oemDiagnosticDataType;
3320 if (!redfish::json_util::readJsonAction(
3321 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3322 "OEMDiagnosticDataType", oemDiagnosticDataType))
3323 {
3324 return;
3325 }
3326
3327 if (diagnosticDataType != "OEM")
3328 {
3329 BMCWEB_LOG_ERROR
3330 << "Only OEM DiagnosticDataType supported for Crashdump";
3331 messages::actionParameterValueFormatError(
3332 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3333 "CollectDiagnosticData");
3334 return;
3335 }
3336
3337 OEMDiagnosticType oemDiagType =
3338 getOEMDiagnosticType(oemDiagnosticDataType);
3339
3340 std::string iface;
3341 std::string method;
3342 std::string taskMatchStr;
3343 if (oemDiagType == OEMDiagnosticType::onDemand)
3344 {
3345 iface = crashdumpOnDemandInterface;
3346 method = "GenerateOnDemandLog";
3347 taskMatchStr = "type='signal',"
3348 "interface='org.freedesktop.DBus.Properties',"
3349 "member='PropertiesChanged',"
3350 "arg0namespace='com.intel.crashdump'";
3351 }
3352 else if (oemDiagType == OEMDiagnosticType::telemetry)
3353 {
3354 iface = crashdumpTelemetryInterface;
3355 method = "GenerateTelemetryLog";
3356 taskMatchStr = "type='signal',"
3357 "interface='org.freedesktop.DBus.Properties',"
3358 "member='PropertiesChanged',"
3359 "arg0namespace='com.intel.crashdump'";
3360 }
3361 else
3362 {
3363 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3364 << oemDiagnosticDataType;
3365 messages::actionParameterValueFormatError(
3366 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3367 "CollectDiagnosticData");
3368 return;
3369 }
3370
3371 auto collectCrashdumpCallback =
3372 [asyncResp, payload(task::Payload(req)),
3373 taskMatchStr](const boost::system::error_code ec,
3374 const std::string&) mutable {
3375 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003376 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003377 if (ec.value() == boost::system::errc::operation_not_supported)
3378 {
3379 messages::resourceInStandby(asyncResp->res);
3380 }
3381 else if (ec.value() ==
3382 boost::system::errc::device_or_resource_busy)
3383 {
3384 messages::serviceTemporarilyUnavailable(asyncResp->res,
3385 "60");
3386 }
3387 else
3388 {
3389 messages::internalError(asyncResp->res);
3390 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003391 return;
3392 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003393 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003394 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003395 const std::shared_ptr<task::TaskData>& taskData) {
3396 if (!err)
3397 {
3398 taskData->messages.emplace_back(messages::taskCompletedOK(
3399 std::to_string(taskData->index)));
3400 taskData->state = "Completed";
3401 }
3402 return task::completed;
3403 },
3404 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003405
Ed Tanous002d39b2022-05-31 08:59:27 -07003406 task->startTimer(std::chrono::minutes(5));
3407 task->populateResp(asyncResp->res);
3408 task->payload.emplace(std::move(payload));
3409 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003410
Ed Tanous002d39b2022-05-31 08:59:27 -07003411 crow::connections::systemBus->async_method_call(
3412 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3413 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003414 });
3415}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003416
Andrew Geisslercb92c032018-08-17 07:56:14 -07003417/**
3418 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3419 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003420inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003421{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003422 /**
3423 * Function handles POST method request.
3424 * The Clear Log actions does not require any parameter.The action deletes
3425 * all entries found in the Entries collection for this Log Service.
3426 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003427
George Liu0fda0f12021-11-16 10:06:17 +08003428 BMCWEB_ROUTE(
3429 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003430 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003431 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003432 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003433 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003434 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3435 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003436 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003437 {
3438 return;
3439 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003440 if (systemName != "system")
3441 {
3442 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3443 systemName);
3444 ;
3445 return;
3446 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003447 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003448
Ed Tanous002d39b2022-05-31 08:59:27 -07003449 // Process response from Logging service.
3450 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3451 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3452 if (ec)
3453 {
3454 // TODO Handle for specific error code
3455 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3456 asyncResp->res.result(
3457 boost::beast::http::status::internal_server_error);
3458 return;
3459 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003460
Ed Tanous002d39b2022-05-31 08:59:27 -07003461 asyncResp->res.result(boost::beast::http::status::no_content);
3462 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003463
Ed Tanous002d39b2022-05-31 08:59:27 -07003464 // Make call to Logging service to request Clear Log
3465 crow::connections::systemBus->async_method_call(
3466 respHandler, "xyz.openbmc_project.Logging",
3467 "/xyz/openbmc_project/logging",
3468 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3469 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003470}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003471
3472/****************************************************
3473 * Redfish PostCode interfaces
3474 * using DBUS interface: getPostCodesTS
3475 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003476inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003477{
Ed Tanous22d268c2022-05-19 09:39:07 -07003478 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003479 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003480 .methods(boost::beast::http::verb::get)(
3481 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3483 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003484 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003485 {
3486 return;
3487 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003488 if (systemName != "system")
3489 {
3490 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3491 systemName);
3492 ;
3493 return;
3494 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003495 asyncResp->res.jsonValue["@odata.id"] =
3496 "/redfish/v1/Systems/system/LogServices/PostCodes";
3497 asyncResp->res.jsonValue["@odata.type"] =
3498 "#LogService.v1_1_0.LogService";
3499 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3500 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3501 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3502 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3503 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3504 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303505
Ed Tanous002d39b2022-05-31 08:59:27 -07003506 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003507 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003508 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3509 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3510 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303511
Ed Tanous002d39b2022-05-31 08:59:27 -07003512 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3513 {"target",
3514 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003515 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003516}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003517
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003518inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003519{
George Liu0fda0f12021-11-16 10:06:17 +08003520 BMCWEB_ROUTE(
3521 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003522 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003523 // The following privilege is incorrect; It should be ConfigureManager
3524 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003525 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003526 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003527 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003528 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3529 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003530 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003531 {
3532 return;
3533 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003534 if (systemName != "system")
3535 {
3536 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3537 systemName);
3538 ;
3539 return;
3540 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003541 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003542
Ed Tanous002d39b2022-05-31 08:59:27 -07003543 // Make call to post-code service to request clear all
3544 crow::connections::systemBus->async_method_call(
3545 [asyncResp](const boost::system::error_code ec) {
3546 if (ec)
3547 {
3548 // TODO Handle for specific error code
3549 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3550 << ec;
3551 asyncResp->res.result(
3552 boost::beast::http::status::internal_server_error);
3553 messages::internalError(asyncResp->res);
3554 return;
3555 }
3556 },
3557 "xyz.openbmc_project.State.Boot.PostCode0",
3558 "/xyz/openbmc_project/State/Boot/PostCode0",
3559 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3560 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003561}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003562
3563static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003564 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303565 const boost::container::flat_map<
3566 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003567 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3568 const uint64_t skip = 0, const uint64_t top = 0)
3569{
3570 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003571 const registries::Message* message =
3572 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003573
3574 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003575 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003576
3577 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303578 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3579 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003580 {
3581 currentCodeIndex++;
3582 std::string postcodeEntryID =
3583 "B" + std::to_string(bootIndex) + "-" +
3584 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3585
3586 uint64_t usecSinceEpoch = code.first;
3587 uint64_t usTimeOffset = 0;
3588
3589 if (1 == currentCodeIndex)
3590 { // already incremented
3591 firstCodeTimeUs = code.first;
3592 }
3593 else
3594 {
3595 usTimeOffset = code.first - firstCodeTimeUs;
3596 }
3597
3598 // skip if no specific codeIndex is specified and currentCodeIndex does
3599 // not fall between top and skip
3600 if ((codeIndex == 0) &&
3601 (currentCodeIndex <= skip || currentCodeIndex > top))
3602 {
3603 continue;
3604 }
3605
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003606 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003607 // currentIndex
3608 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3609 {
3610 // This is done for simplicity. 1st entry is needed to calculate
3611 // time offset. To improve efficiency, one can get to the entry
3612 // directly (possibly with flatmap's nth method)
3613 continue;
3614 }
3615
3616 // currentCodeIndex is within top and skip or equal to specified code
3617 // index
3618
3619 // Get the Created time from the timestamp
3620 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003621 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003622 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003623
3624 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3625 std::ostringstream hexCode;
3626 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303627 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003628 std::ostringstream timeOffsetStr;
3629 // Set Fixed -Point Notation
3630 timeOffsetStr << std::fixed;
3631 // Set precision to 4 digits
3632 timeOffsetStr << std::setprecision(4);
3633 // Add double to stream
3634 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3635 std::vector<std::string> messageArgs = {
3636 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3637
3638 // Get MessageArgs template from message registry
3639 std::string msg;
3640 if (message != nullptr)
3641 {
3642 msg = message->message;
3643
3644 // fill in this post code value
3645 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003646 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003647 {
3648 std::string argStr = "%" + std::to_string(++i);
3649 size_t argPos = msg.find(argStr);
3650 if (argPos != std::string::npos)
3651 {
3652 msg.replace(argPos, argStr.length(), messageArg);
3653 }
3654 }
3655 }
3656
Tim Leed4342a92020-04-27 11:47:58 +08003657 // Get Severity template from message registry
3658 std::string severity;
3659 if (message != nullptr)
3660 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003661 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003662 }
3663
ZhikuiRena3316fc2020-01-29 14:58:08 -08003664 // add to AsyncResp
3665 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003666 nlohmann::json& bmcLogEntry = logEntryArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05003667 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003668 bmcLogEntry["@odata.id"] =
3669 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3670 postcodeEntryID;
3671 bmcLogEntry["Name"] = "POST Code Log Entry";
3672 bmcLogEntry["Id"] = postcodeEntryID;
3673 bmcLogEntry["Message"] = std::move(msg);
3674 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3675 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3676 bmcLogEntry["EntryType"] = "Event";
3677 bmcLogEntry["Severity"] = std::move(severity);
3678 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003679 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3680 {
3681 bmcLogEntry["AdditionalDataURI"] =
3682 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3683 postcodeEntryID + "/attachment";
3684 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003685 }
3686}
3687
zhanghch058d1b46d2021-04-01 11:18:24 +08003688static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003689 const uint16_t bootIndex,
3690 const uint64_t codeIndex)
3691{
3692 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303693 [aResp, bootIndex,
3694 codeIndex](const boost::system::error_code ec,
3695 const boost::container::flat_map<
3696 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3697 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003698 if (ec)
3699 {
3700 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3701 messages::internalError(aResp->res);
3702 return;
3703 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003704
Ed Tanous002d39b2022-05-31 08:59:27 -07003705 // skip the empty postcode boots
3706 if (postcode.empty())
3707 {
3708 return;
3709 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003710
Ed Tanous002d39b2022-05-31 08:59:27 -07003711 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003712
Ed Tanous002d39b2022-05-31 08:59:27 -07003713 aResp->res.jsonValue["Members@odata.count"] =
3714 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003715 },
Jonathan Doman15124762021-01-07 17:54:17 -08003716 "xyz.openbmc_project.State.Boot.PostCode0",
3717 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003718 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3719 bootIndex);
3720}
3721
zhanghch058d1b46d2021-04-01 11:18:24 +08003722static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003723 const uint16_t bootIndex,
3724 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003725 const uint64_t entryCount, size_t skip,
3726 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003727{
3728 crow::connections::systemBus->async_method_call(
3729 [aResp, bootIndex, bootCount, entryCount, skip,
3730 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303731 const boost::container::flat_map<
3732 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3733 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003734 if (ec)
3735 {
3736 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3737 messages::internalError(aResp->res);
3738 return;
3739 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003740
Ed Tanous002d39b2022-05-31 08:59:27 -07003741 uint64_t endCount = entryCount;
3742 if (!postcode.empty())
3743 {
3744 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003745 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003746 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003747 uint64_t thisBootSkip =
3748 std::max(static_cast<uint64_t>(skip), entryCount) -
3749 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003750 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003751 std::min(static_cast<uint64_t>(top + skip), endCount) -
3752 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003753
3754 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3755 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003756 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003757 aResp->res.jsonValue["Members@odata.count"] = endCount;
3758 }
3759
3760 // continue to previous bootIndex
3761 if (bootIndex < bootCount)
3762 {
3763 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3764 bootCount, endCount, skip, top);
3765 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003766 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003767 {
3768 aResp->res.jsonValue["Members@odata.nextLink"] =
3769 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3770 std::to_string(skip + top);
3771 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003772 },
Jonathan Doman15124762021-01-07 17:54:17 -08003773 "xyz.openbmc_project.State.Boot.PostCode0",
3774 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003775 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3776 bootIndex);
3777}
3778
zhanghch058d1b46d2021-04-01 11:18:24 +08003779static void
3780 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003781 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003782{
3783 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003784 sdbusplus::asio::getProperty<uint16_t>(
3785 *crow::connections::systemBus,
3786 "xyz.openbmc_project.State.Boot.PostCode0",
3787 "/xyz/openbmc_project/State/Boot/PostCode0",
3788 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3789 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3790 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003791 if (ec)
3792 {
3793 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3794 messages::internalError(aResp->res);
3795 return;
3796 }
3797 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003798 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003799}
3800
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003801inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003802{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003803 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003804 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003805 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003806 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003807 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003808 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3809 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003810 query_param::QueryCapabilities capabilities = {
3811 .canDelegateTop = true,
3812 .canDelegateSkip = true,
3813 };
3814 query_param::Query delegatedQuery;
3815 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003816 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003817 {
3818 return;
3819 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003820
3821 if (systemName != "system")
3822 {
3823 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3824 systemName);
3825 ;
3826 return;
3827 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003828 asyncResp->res.jsonValue["@odata.type"] =
3829 "#LogEntryCollection.LogEntryCollection";
3830 asyncResp->res.jsonValue["@odata.id"] =
3831 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3832 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3833 asyncResp->res.jsonValue["Description"] =
3834 "Collection of POST Code Log Entries";
3835 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3836 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003837 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003838 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003839 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003840 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003841}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003842
George Liu647b3cd2021-07-05 12:43:56 +08003843/**
3844 * @brief Parse post code ID and get the current value and index value
3845 * eg: postCodeID=B1-2, currentValue=1, index=2
3846 *
3847 * @param[in] postCodeID Post Code ID
3848 * @param[out] currentValue Current value
3849 * @param[out] index Index value
3850 *
3851 * @return bool true if the parsing is successful, false the parsing fails
3852 */
3853inline static bool parsePostCode(const std::string& postCodeID,
3854 uint64_t& currentValue, uint16_t& index)
3855{
3856 std::vector<std::string> split;
3857 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3858 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3859 {
3860 return false;
3861 }
3862
Ed Tanousca45aa32022-01-07 09:28:45 -08003863 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003864 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003865 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003866 const char* end = split[0].data() + split[0].size();
3867 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3868
3869 if (ptrIndex != end || ecIndex != std::errc())
3870 {
3871 return false;
3872 }
3873
3874 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003875
3876 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003877 end = split[1].data() + split[1].size();
3878 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003879
Tony Lee517d9a52022-06-28 15:41:23 +08003880 return ptrValue == end && ecValue == std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003881}
3882
3883inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3884{
George Liu0fda0f12021-11-16 10:06:17 +08003885 BMCWEB_ROUTE(
3886 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003887 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003888 .privileges(redfish::privileges::getLogEntry)
3889 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003890 [&app](const crow::Request& req,
3891 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003892 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003893 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003894 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003895 {
3896 return;
3897 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003898 if (http_helpers::isContentTypeAllowed(
3899 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003900 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003901 {
3902 asyncResp->res.result(boost::beast::http::status::bad_request);
3903 return;
3904 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003905 if (systemName != "system")
3906 {
3907 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3908 systemName);
3909 ;
3910 return;
3911 }
George Liu647b3cd2021-07-05 12:43:56 +08003912
Ed Tanous002d39b2022-05-31 08:59:27 -07003913 uint64_t currentValue = 0;
3914 uint16_t index = 0;
3915 if (!parsePostCode(postCodeID, currentValue, index))
3916 {
3917 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3918 return;
3919 }
George Liu647b3cd2021-07-05 12:43:56 +08003920
Ed Tanous002d39b2022-05-31 08:59:27 -07003921 crow::connections::systemBus->async_method_call(
3922 [asyncResp, postCodeID, currentValue](
3923 const boost::system::error_code ec,
3924 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3925 postcodes) {
3926 if (ec.value() == EBADR)
3927 {
3928 messages::resourceNotFound(asyncResp->res, "LogEntry",
3929 postCodeID);
3930 return;
3931 }
3932 if (ec)
3933 {
3934 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3935 messages::internalError(asyncResp->res);
3936 return;
3937 }
George Liu647b3cd2021-07-05 12:43:56 +08003938
Ed Tanous002d39b2022-05-31 08:59:27 -07003939 size_t value = static_cast<size_t>(currentValue) - 1;
3940 if (value == std::string::npos || postcodes.size() < currentValue)
3941 {
3942 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3943 messages::resourceNotFound(asyncResp->res, "LogEntry",
3944 postCodeID);
3945 return;
3946 }
George Liu647b3cd2021-07-05 12:43:56 +08003947
Ed Tanous002d39b2022-05-31 08:59:27 -07003948 const auto& [tID, c] = postcodes[value];
3949 if (c.empty())
3950 {
3951 BMCWEB_LOG_INFO << "No found post code data";
3952 messages::resourceNotFound(asyncResp->res, "LogEntry",
3953 postCodeID);
3954 return;
3955 }
3956 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3957 const char* d = reinterpret_cast<const char*>(c.data());
3958 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003959
Ed Tanousd9f6c622022-03-17 09:12:17 -07003960 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07003961 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07003962 asyncResp->res.addHeader(
3963 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07003964 asyncResp->res.body() = crow::utility::base64encode(strData);
3965 },
3966 "xyz.openbmc_project.State.Boot.PostCode0",
3967 "/xyz/openbmc_project/State/Boot/PostCode0",
3968 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3969 });
George Liu647b3cd2021-07-05 12:43:56 +08003970}
3971
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003972inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003973{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003974 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003975 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003976 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003977 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003978 [&app](const crow::Request& req,
3979 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003980 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003981 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003982 {
3983 return;
3984 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003985 if (systemName != "system")
3986 {
3987 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3988 systemName);
3989 return;
3990 }
3991
Ed Tanous002d39b2022-05-31 08:59:27 -07003992 uint16_t bootIndex = 0;
3993 uint64_t codeIndex = 0;
3994 if (!parsePostCode(targetID, codeIndex, bootIndex))
3995 {
3996 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003997 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003998 return;
3999 }
4000 if (bootIndex == 0 || codeIndex == 0)
4001 {
4002 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
4003 << targetID;
4004 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004005
Vijay Lobo9c11a172021-10-07 16:53:16 -05004006 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07004007 asyncResp->res.jsonValue["@odata.id"] =
4008 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
4009 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4010 asyncResp->res.jsonValue["Description"] =
4011 "Collection of POST Code Log Entries";
4012 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4013 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004014
Ed Tanous002d39b2022-05-31 08:59:27 -07004015 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
4016 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004017}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004018
Ed Tanous1da66f72018-07-27 16:13:37 -07004019} // namespace redfish