blob: 33440fb1e25fa0c8f0d15e57822fc4c2887dfa5e [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](
Patrick Williams5b378542022-11-26 09:41:59 -0600770 boost::system::error_code err, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600771 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(
Patrick Williams5b378542022-11-26 09:41:59 -0600901 [asyncResp, payload(task::Payload(req)), dumpPath](
902 const boost::system::error_code ec, const sdbusplus::message_t& msg,
903 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700904 if (ec)
905 {
906 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500907 const sd_bus_error* dbusError = msg.get_error();
908 if (dbusError == nullptr)
909 {
910 messages::internalError(asyncResp->res);
911 return;
912 }
913
914 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
915 << " and error msg: " << dbusError->message;
916 if (std::string_view(
917 "xyz.openbmc_project.Common.Error.NotAllowed") ==
918 dbusError->name)
919 {
920 messages::resourceInStandby(asyncResp->res);
921 return;
922 }
923 if (std::string_view(
924 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
925 dbusError->name)
926 {
927 messages::serviceDisabled(asyncResp->res, dumpPath);
928 return;
929 }
930 if (std::string_view(
931 "xyz.openbmc_project.Common.Error.Unavailable") ==
932 dbusError->name)
933 {
934 messages::resourceInUse(asyncResp->res);
935 return;
936 }
937 // Other Dbus errors such as:
938 // xyz.openbmc_project.Common.Error.InvalidArgument &
939 // org.freedesktop.DBus.Error.InvalidArgs are all related to
940 // the dbus call that is made here in the bmcweb
941 // implementation and has nothing to do with the client's
942 // input in the request. Hence, returning internal error
943 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700944 messages::internalError(asyncResp->res);
945 return;
946 }
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600947 BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str;
948 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500949 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500950 "xyz.openbmc_project.Dump.Manager",
951 "/xyz/openbmc_project/dump/" +
952 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600953 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500954}
955
zhanghch058d1b46d2021-04-01 11:18:24 +0800956inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
957 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500958{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500959 std::string dumpTypeLowerCopy =
960 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800961
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500962 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800963 [asyncResp, dumpType](
964 const boost::system::error_code ec,
965 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700966 if (ec)
967 {
968 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
969 messages::internalError(asyncResp->res);
970 return;
971 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500972
Ed Tanous002d39b2022-05-31 08:59:27 -0700973 for (const std::string& path : subTreePaths)
974 {
975 sdbusplus::message::object_path objPath(path);
976 std::string logID = objPath.filename();
977 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500978 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700979 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500980 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700981 deleteDumpEntry(asyncResp, logID, dumpType);
982 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500983 },
984 "xyz.openbmc_project.ObjectMapper",
985 "/xyz/openbmc_project/object_mapper",
986 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500987 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
988 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
989 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500990}
991
Ed Tanousb9d36b42022-02-26 21:42:46 -0800992inline static void
993 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
994 std::string& filename, std::string& timestamp,
995 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700996{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200997 const std::string* filenamePtr = nullptr;
998 const std::string* timestampPtr = nullptr;
999 const std::string* logfilePtr = nullptr;
1000
1001 const bool success = sdbusplus::unpackPropertiesNoThrow(
1002 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1003 "Filename", filenamePtr, "Log", logfilePtr);
1004
1005 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001006 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001007 return;
1008 }
1009
1010 if (filenamePtr != nullptr)
1011 {
1012 filename = *filenamePtr;
1013 }
1014
1015 if (timestampPtr != nullptr)
1016 {
1017 timestamp = *timestampPtr;
1018 }
1019
1020 if (logfilePtr != nullptr)
1021 {
1022 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001023 }
1024}
1025
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001026constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001027inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001028{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001029 /**
1030 * Functions triggers appropriate requests on DBus
1031 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001032 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001033 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001034 .methods(boost::beast::http::verb::get)(
1035 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001036 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1037 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001038 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001039 {
1040 return;
1041 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001042 if (systemName != "system")
1043 {
1044 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1045 systemName);
1046 return;
1047 }
1048
Ed Tanous002d39b2022-05-31 08:59:27 -07001049 // Collections don't include the static data added by SubRoute
1050 // because it has a duplicate entry for members
1051 asyncResp->res.jsonValue["@odata.type"] =
1052 "#LogServiceCollection.LogServiceCollection";
1053 asyncResp->res.jsonValue["@odata.id"] =
1054 "/redfish/v1/Systems/system/LogServices";
1055 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1056 asyncResp->res.jsonValue["Description"] =
1057 "Collection of LogServices for this Computer System";
1058 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1059 logServiceArray = nlohmann::json::array();
1060 nlohmann::json::object_t eventLog;
1061 eventLog["@odata.id"] =
1062 "/redfish/v1/Systems/system/LogServices/EventLog";
1063 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001064#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001065 nlohmann::json::object_t dumpLog;
1066 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
1067 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -06001068#endif
1069
Jason M. Billsd53dd412019-02-12 17:16:22 -08001070#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001071 nlohmann::json::object_t crashdump;
1072 crashdump["@odata.id"] =
1073 "/redfish/v1/Systems/system/LogServices/Crashdump";
1074 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -08001075#endif
Spencer Kub7028eb2021-10-26 15:27:35 +08001076
1077#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -07001078 nlohmann::json::object_t hostlogger;
1079 hostlogger["@odata.id"] =
1080 "/redfish/v1/Systems/system/LogServices/HostLogger";
1081 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +08001082#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07001083 asyncResp->res.jsonValue["Members@odata.count"] =
1084 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001085
Ed Tanous002d39b2022-05-31 08:59:27 -07001086 crow::connections::systemBus->async_method_call(
1087 [asyncResp](const boost::system::error_code ec,
1088 const dbus::utility::MapperGetSubTreePathsResponse&
1089 subtreePath) {
1090 if (ec)
1091 {
1092 BMCWEB_LOG_ERROR << ec;
1093 return;
1094 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001095
Ed Tanous002d39b2022-05-31 08:59:27 -07001096 for (const auto& pathStr : subtreePath)
1097 {
1098 if (pathStr.find("PostCode") != std::string::npos)
1099 {
1100 nlohmann::json& logServiceArrayLocal =
1101 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001102 nlohmann::json::object_t member;
1103 member["@odata.id"] =
1104 "/redfish/v1/Systems/system/LogServices/PostCodes";
1105
1106 logServiceArrayLocal.push_back(std::move(member));
1107
Ed Tanous002d39b2022-05-31 08:59:27 -07001108 asyncResp->res.jsonValue["Members@odata.count"] =
1109 logServiceArrayLocal.size();
1110 return;
1111 }
1112 }
1113 },
1114 "xyz.openbmc_project.ObjectMapper",
1115 "/xyz/openbmc_project/object_mapper",
1116 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
1117 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -07001118 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001119}
1120
1121inline void requestRoutesEventLogService(App& app)
1122{
Ed Tanous22d268c2022-05-19 09:39:07 -07001123 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001124 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001125 .methods(boost::beast::http::verb::get)(
1126 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001127 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1128 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001129 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001130 {
1131 return;
1132 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001133 if (systemName != "system")
1134 {
1135 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1136 systemName);
1137 return;
1138 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001139 asyncResp->res.jsonValue["@odata.id"] =
1140 "/redfish/v1/Systems/system/LogServices/EventLog";
1141 asyncResp->res.jsonValue["@odata.type"] =
1142 "#LogService.v1_1_0.LogService";
1143 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1144 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1145 asyncResp->res.jsonValue["Id"] = "EventLog";
1146 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301147
Ed Tanous002d39b2022-05-31 08:59:27 -07001148 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001149 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301150
Ed Tanous002d39b2022-05-31 08:59:27 -07001151 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1152 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1153 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301154
Ed Tanous002d39b2022-05-31 08:59:27 -07001155 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1156 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1157 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001158
Ed Tanous002d39b2022-05-31 08:59:27 -07001159 {"target",
1160 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001161 });
1162}
1163
1164inline void requestRoutesJournalEventLogClear(App& app)
1165{
Jason M. Bills4978b632022-02-22 14:17:43 -08001166 BMCWEB_ROUTE(
1167 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001168 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001169 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001170 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001171 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001172 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1173 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001174 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001175 {
1176 return;
1177 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001178 if (systemName != "system")
1179 {
1180 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1181 systemName);
1182 return;
1183 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001184 // Clear the EventLog by deleting the log files
1185 std::vector<std::filesystem::path> redfishLogFiles;
1186 if (getRedfishLogFiles(redfishLogFiles))
1187 {
1188 for (const std::filesystem::path& file : redfishLogFiles)
1189 {
1190 std::error_code ec;
1191 std::filesystem::remove(file, ec);
1192 }
1193 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001194
Ed Tanous002d39b2022-05-31 08:59:27 -07001195 // Reload rsyslog so it knows to start new log files
1196 crow::connections::systemBus->async_method_call(
1197 [asyncResp](const boost::system::error_code ec) {
1198 if (ec)
1199 {
1200 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1201 messages::internalError(asyncResp->res);
1202 return;
1203 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001204
Ed Tanous002d39b2022-05-31 08:59:27 -07001205 messages::success(asyncResp->res);
1206 },
1207 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1208 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1209 "replace");
1210 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001211}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001212
Jason M. Billsac992cd2022-06-24 13:31:46 -07001213enum class LogParseError
1214{
1215 success,
1216 parseFailed,
1217 messageIdNotInRegistry,
1218};
1219
1220static LogParseError
1221 fillEventLogEntryJson(const std::string& logEntryID,
1222 const std::string& logEntry,
1223 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001224{
Jason M. Bills95820182019-04-22 16:25:34 -07001225 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001226 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001227 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001228 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001229 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001230 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001231 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001232 std::string timestamp = logEntry.substr(0, space);
1233 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001234 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001235 if (entryStart == std::string::npos)
1236 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001237 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001238 }
1239 std::string_view entry(logEntry);
1240 entry.remove_prefix(entryStart);
1241 // Use split to separate the entry into its fields
1242 std::vector<std::string> logEntryFields;
1243 boost::split(logEntryFields, entry, boost::is_any_of(","),
1244 boost::token_compress_on);
1245 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001246 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001247 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001248 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001249 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001250 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001251
Jason M. Bills4851d452019-03-28 11:27:48 -07001252 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001253 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001254
Sui Chen54417b02022-03-24 14:59:52 -07001255 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001256 {
Sui Chen54417b02022-03-24 14:59:52 -07001257 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001258 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001259 }
1260
Sui Chen54417b02022-03-24 14:59:52 -07001261 std::string msg = message->message;
1262
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001263 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001264 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001265 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001266 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001267 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001268 // If the first string is empty, assume there are no MessageArgs
1269 std::size_t messageArgsSize = 0;
1270 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001271 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001272 messageArgsSize = logEntryFields.size() - 1;
1273 }
1274
Ed Tanous23a21a12020-07-25 04:45:05 +00001275 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001276
1277 // Fill the MessageArgs into the Message
1278 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001279 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001280 {
1281 std::string argStr = "%" + std::to_string(++i);
1282 size_t argPos = msg.find(argStr);
1283 if (argPos != std::string::npos)
1284 {
1285 msg.replace(argPos, argStr.length(), messageArg);
1286 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001287 }
1288 }
1289
Jason M. Bills95820182019-04-22 16:25:34 -07001290 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1291 // format which matches the Redfish format except for the fractional seconds
1292 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001293 std::size_t dot = timestamp.find_first_of('.');
1294 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001295 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001296 {
Jason M. Bills95820182019-04-22 16:25:34 -07001297 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001298 }
1299
1300 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001301 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001302 logEntryJson["@odata.id"] =
1303 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1304 logEntryJson["Name"] = "System Event Log Entry";
1305 logEntryJson["Id"] = logEntryID;
1306 logEntryJson["Message"] = std::move(msg);
1307 logEntryJson["MessageId"] = std::move(messageID);
1308 logEntryJson["MessageArgs"] = messageArgs;
1309 logEntryJson["EntryType"] = "Event";
1310 logEntryJson["Severity"] = message->messageSeverity;
1311 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001312 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001313}
1314
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001315inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001316{
Ed Tanous22d268c2022-05-19 09:39:07 -07001317 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001318 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001319 .methods(boost::beast::http::verb::get)(
1320 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001321 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1322 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001323 query_param::QueryCapabilities capabilities = {
1324 .canDelegateTop = true,
1325 .canDelegateSkip = true,
1326 };
1327 query_param::Query delegatedQuery;
1328 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001329 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001330 {
1331 return;
1332 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001333 if (systemName != "system")
1334 {
1335 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1336 systemName);
1337 return;
1338 }
1339
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001340 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001341 size_t skip = delegatedQuery.skip.value_or(0);
1342
Ed Tanous002d39b2022-05-31 08:59:27 -07001343 // Collections don't include the static data added by SubRoute
1344 // because it has a duplicate entry for members
1345 asyncResp->res.jsonValue["@odata.type"] =
1346 "#LogEntryCollection.LogEntryCollection";
1347 asyncResp->res.jsonValue["@odata.id"] =
1348 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1349 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1350 asyncResp->res.jsonValue["Description"] =
1351 "Collection of System Event Log Entries";
1352
1353 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1354 logEntryArray = nlohmann::json::array();
1355 // Go through the log files and create a unique ID for each
1356 // entry
1357 std::vector<std::filesystem::path> redfishLogFiles;
1358 getRedfishLogFiles(redfishLogFiles);
1359 uint64_t entryCount = 0;
1360 std::string logEntry;
1361
1362 // Oldest logs are in the last file, so start there and loop
1363 // backwards
1364 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1365 it++)
1366 {
1367 std::ifstream logStream(*it);
1368 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001369 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001370 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001371 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001372
Ed Tanous002d39b2022-05-31 08:59:27 -07001373 // Reset the unique ID on the first entry
1374 bool firstEntry = true;
1375 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001376 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001377 std::string idStr;
1378 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001379 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001380 continue;
1381 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001382 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001383
Jason M. Billsde703c52022-06-23 14:19:04 -07001384 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001385 LogParseError status =
1386 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1387 if (status == LogParseError::messageIdNotInRegistry)
1388 {
1389 continue;
1390 }
1391 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 {
1393 messages::internalError(asyncResp->res);
1394 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001395 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001396
Jason M. Billsde703c52022-06-23 14:19:04 -07001397 entryCount++;
1398 // Handle paging using skip (number of entries to skip from the
1399 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001400 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001401 {
1402 continue;
1403 }
1404
1405 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001406 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 }
1408 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001409 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 {
1411 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1412 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001413 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001414 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001415 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001416}
Chicago Duan336e96c2019-07-15 14:22:08 +08001417
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001418inline void requestRoutesJournalEventLogEntry(App& app)
1419{
1420 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001421 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001422 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001423 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001424 [&app](const crow::Request& req,
1425 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001426 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001427 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001428 {
1429 return;
1430 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001431
1432 if (systemName != "system")
1433 {
1434 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1435 systemName);
1436 return;
1437 }
1438
Ed Tanous002d39b2022-05-31 08:59:27 -07001439 const std::string& targetID = param;
1440
1441 // Go through the log files and check the unique ID for each
1442 // entry to find the target entry
1443 std::vector<std::filesystem::path> redfishLogFiles;
1444 getRedfishLogFiles(redfishLogFiles);
1445 std::string logEntry;
1446
1447 // Oldest logs are in the last file, so start there and loop
1448 // backwards
1449 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1450 it++)
1451 {
1452 std::ifstream logStream(*it);
1453 if (!logStream.is_open())
1454 {
1455 continue;
1456 }
1457
1458 // Reset the unique ID on the first entry
1459 bool firstEntry = true;
1460 while (std::getline(logStream, logEntry))
1461 {
1462 std::string idStr;
1463 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001464 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001465 continue;
1466 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001467 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001468
1469 if (idStr == targetID)
1470 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001471 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001472 LogParseError status =
1473 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1474 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001475 {
1476 messages::internalError(asyncResp->res);
1477 return;
1478 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001479 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001480 return;
1481 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001482 }
1483 }
1484 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001485 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07001486 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001487}
1488
1489inline void requestRoutesDBusEventLogEntryCollection(App& app)
1490{
Ed Tanous22d268c2022-05-19 09:39:07 -07001491 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001492 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001493 .methods(boost::beast::http::verb::get)(
1494 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001495 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1496 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001497 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001498 {
1499 return;
1500 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001501 if (systemName != "system")
1502 {
1503 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1504 systemName);
1505 return;
1506 }
1507
Ed Tanous002d39b2022-05-31 08:59:27 -07001508 // Collections don't include the static data added by SubRoute
1509 // because it has a duplicate entry for members
1510 asyncResp->res.jsonValue["@odata.type"] =
1511 "#LogEntryCollection.LogEntryCollection";
1512 asyncResp->res.jsonValue["@odata.id"] =
1513 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1514 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1515 asyncResp->res.jsonValue["Description"] =
1516 "Collection of System Event Log Entries";
1517
1518 // DBus implementation of EventLog/Entries
1519 // Make call to Logging Service to find all log entry objects
1520 crow::connections::systemBus->async_method_call(
1521 [asyncResp](const boost::system::error_code ec,
1522 const dbus::utility::ManagedObjectType& resp) {
1523 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001524 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001525 // TODO Handle for specific error code
1526 BMCWEB_LOG_ERROR
1527 << "getLogEntriesIfaceData resp_handler got error " << ec;
1528 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001529 return;
1530 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001531 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1532 entriesArray = nlohmann::json::array();
1533 for (const auto& objectPath : resp)
1534 {
1535 const uint32_t* id = nullptr;
1536 const uint64_t* timestamp = nullptr;
1537 const uint64_t* updateTimestamp = nullptr;
1538 const std::string* severity = nullptr;
1539 const std::string* message = nullptr;
1540 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001541 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001542 bool resolved = false;
1543 for (const auto& interfaceMap : objectPath.second)
1544 {
1545 if (interfaceMap.first ==
1546 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001547 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001548 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001549 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001550 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001551 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001552 id = std::get_if<uint32_t>(&propertyMap.second);
1553 }
1554 else if (propertyMap.first == "Timestamp")
1555 {
1556 timestamp =
1557 std::get_if<uint64_t>(&propertyMap.second);
1558 }
1559 else if (propertyMap.first == "UpdateTimestamp")
1560 {
1561 updateTimestamp =
1562 std::get_if<uint64_t>(&propertyMap.second);
1563 }
1564 else if (propertyMap.first == "Severity")
1565 {
1566 severity = std::get_if<std::string>(
1567 &propertyMap.second);
1568 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001569 else if (propertyMap.first == "Resolution")
1570 {
1571 resolution = std::get_if<std::string>(
1572 &propertyMap.second);
1573 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001574 else if (propertyMap.first == "Message")
1575 {
1576 message = std::get_if<std::string>(
1577 &propertyMap.second);
1578 }
1579 else if (propertyMap.first == "Resolved")
1580 {
1581 const bool* resolveptr =
1582 std::get_if<bool>(&propertyMap.second);
1583 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001584 {
1585 messages::internalError(asyncResp->res);
1586 return;
1587 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001588 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001589 }
1590 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001591 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001592 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001593 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001594 messages::internalError(asyncResp->res);
1595 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001596 }
1597 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001598 else if (interfaceMap.first ==
1599 "xyz.openbmc_project.Common.FilePath")
1600 {
1601 for (const auto& propertyMap : interfaceMap.second)
1602 {
1603 if (propertyMap.first == "Path")
1604 {
1605 filePath = std::get_if<std::string>(
1606 &propertyMap.second);
1607 }
1608 }
1609 }
1610 }
1611 // Object path without the
1612 // xyz.openbmc_project.Logging.Entry interface, ignore
1613 // and continue.
1614 if (id == nullptr || message == nullptr ||
1615 severity == nullptr || timestamp == nullptr ||
1616 updateTimestamp == nullptr)
1617 {
1618 continue;
1619 }
1620 entriesArray.push_back({});
1621 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001622 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 thisEntry["@odata.id"] =
1624 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1625 std::to_string(*id);
1626 thisEntry["Name"] = "System Event Log Entry";
1627 thisEntry["Id"] = std::to_string(*id);
1628 thisEntry["Message"] = *message;
1629 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001630 if ((resolution != nullptr) && (!(*resolution).empty()))
1631 {
1632 thisEntry["Resolution"] = *resolution;
1633 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001634 thisEntry["EntryType"] = "Event";
1635 thisEntry["Severity"] =
1636 translateSeverityDbusToRedfish(*severity);
1637 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001638 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001639 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001640 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001641 if (filePath != nullptr)
1642 {
1643 thisEntry["AdditionalDataURI"] =
1644 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1645 std::to_string(*id) + "/attachment";
1646 }
1647 }
1648 std::sort(
1649 entriesArray.begin(), entriesArray.end(),
1650 [](const nlohmann::json& left, const nlohmann::json& right) {
1651 return (left["Id"] <= right["Id"]);
1652 });
1653 asyncResp->res.jsonValue["Members@odata.count"] =
1654 entriesArray.size();
1655 },
1656 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1657 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001658 });
1659}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001660
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001661inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001662{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001663 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001664 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001665 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001666 .methods(boost::beast::http::verb::get)(
1667 [&app](const crow::Request& req,
1668 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001669 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001670 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001671 {
1672 return;
1673 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001674 if (systemName != "system")
1675 {
1676 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1677 systemName);
1678 return;
1679 }
1680
Ed Tanous002d39b2022-05-31 08:59:27 -07001681 std::string entryID = param;
1682 dbus::utility::escapePathForDbus(entryID);
1683
1684 // DBus implementation of EventLog/Entries
1685 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001686 sdbusplus::asio::getAllProperties(
1687 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1688 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001689 [asyncResp, entryID](const boost::system::error_code ec,
1690 const dbus::utility::DBusPropertiesMap& resp) {
1691 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001692 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001693 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1694 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001695 return;
1696 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001697 if (ec)
1698 {
1699 BMCWEB_LOG_ERROR
1700 << "EventLogEntry (DBus) resp_handler got error " << ec;
1701 messages::internalError(asyncResp->res);
1702 return;
1703 }
1704 const uint32_t* id = nullptr;
1705 const uint64_t* timestamp = nullptr;
1706 const uint64_t* updateTimestamp = nullptr;
1707 const std::string* severity = nullptr;
1708 const std::string* message = nullptr;
1709 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001710 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001711 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001712
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001713 const bool success = sdbusplus::unpackPropertiesNoThrow(
1714 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1715 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001716 severity, "Message", message, "Resolved", resolved,
1717 "Resolution", resolution, "Path", filePath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001718
1719 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001720 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001721 messages::internalError(asyncResp->res);
1722 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001723 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001724
Ed Tanous002d39b2022-05-31 08:59:27 -07001725 if (id == nullptr || message == nullptr || severity == nullptr ||
1726 timestamp == nullptr || updateTimestamp == nullptr)
1727 {
1728 messages::internalError(asyncResp->res);
1729 return;
1730 }
1731 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001732 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001733 asyncResp->res.jsonValue["@odata.id"] =
1734 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1735 std::to_string(*id);
1736 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1737 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1738 asyncResp->res.jsonValue["Message"] = *message;
1739 asyncResp->res.jsonValue["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001740 if ((resolution != nullptr) && (!(*resolution).empty()))
1741 {
1742 asyncResp->res.jsonValue["Resolution"] = *resolution;
1743 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001744 asyncResp->res.jsonValue["EntryType"] = "Event";
1745 asyncResp->res.jsonValue["Severity"] =
1746 translateSeverityDbusToRedfish(*severity);
1747 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001748 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001749 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001750 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001751 if (filePath != nullptr)
1752 {
1753 asyncResp->res.jsonValue["AdditionalDataURI"] =
1754 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1755 std::to_string(*id) + "/attachment";
1756 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001757 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001758 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001759
1760 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001761 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001762 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001763 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001764 [&app](const crow::Request& req,
1765 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001766 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001767 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001768 {
1769 return;
1770 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001771 if (systemName != "system")
1772 {
1773 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1774 systemName);
1775 return;
1776 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001777 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001778
Ed Tanous002d39b2022-05-31 08:59:27 -07001779 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1780 resolved))
1781 {
1782 return;
1783 }
1784 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001785
Ed Tanous002d39b2022-05-31 08:59:27 -07001786 crow::connections::systemBus->async_method_call(
1787 [asyncResp, entryId](const boost::system::error_code ec) {
1788 if (ec)
1789 {
1790 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1791 messages::internalError(asyncResp->res);
1792 return;
1793 }
1794 },
1795 "xyz.openbmc_project.Logging",
1796 "/xyz/openbmc_project/logging/entry/" + entryId,
1797 "org.freedesktop.DBus.Properties", "Set",
1798 "xyz.openbmc_project.Logging.Entry", "Resolved",
1799 dbus::utility::DbusVariantType(*resolved));
1800 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001801
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001802 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001803 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001804 .privileges(redfish::privileges::deleteLogEntry)
1805
Ed Tanous002d39b2022-05-31 08:59:27 -07001806 .methods(boost::beast::http::verb::delete_)(
1807 [&app](const crow::Request& req,
1808 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001809 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001810 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001811 {
1812 return;
1813 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001814 if (systemName != "system")
1815 {
1816 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1817 systemName);
1818 return;
1819 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001820 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1821
1822 std::string entryID = param;
1823
1824 dbus::utility::escapePathForDbus(entryID);
1825
1826 // Process response from Logging service.
1827 auto respHandler =
1828 [asyncResp, entryID](const boost::system::error_code ec) {
1829 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1830 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001831 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001832 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001833 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001834 messages::resourceNotFound(asyncResp->res, "LogEntry",
1835 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001836 return;
1837 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001838 // TODO Handle for specific error code
1839 BMCWEB_LOG_ERROR
1840 << "EventLogEntry (DBus) doDelete respHandler got error "
1841 << ec;
1842 asyncResp->res.result(
1843 boost::beast::http::status::internal_server_error);
1844 return;
1845 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001846
Ed Tanous002d39b2022-05-31 08:59:27 -07001847 asyncResp->res.result(boost::beast::http::status::ok);
1848 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001849
Ed Tanous002d39b2022-05-31 08:59:27 -07001850 // Make call to Logging service to request Delete Log
1851 crow::connections::systemBus->async_method_call(
1852 respHandler, "xyz.openbmc_project.Logging",
1853 "/xyz/openbmc_project/logging/entry/" + entryID,
1854 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001855 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001856}
1857
1858inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001859{
George Liu0fda0f12021-11-16 10:06:17 +08001860 BMCWEB_ROUTE(
1861 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001862 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001863 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001864 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001865 [&app](const crow::Request& req,
1866 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001867 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001868 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001869 {
1870 return;
1871 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001872 if (http_helpers::isContentTypeAllowed(
1873 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001874 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001875 {
1876 asyncResp->res.result(boost::beast::http::status::bad_request);
1877 return;
1878 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001879 if (systemName != "system")
1880 {
1881 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1882 systemName);
1883 return;
1884 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001885
Ed Tanous002d39b2022-05-31 08:59:27 -07001886 std::string entryID = param;
1887 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001888
Ed Tanous002d39b2022-05-31 08:59:27 -07001889 crow::connections::systemBus->async_method_call(
1890 [asyncResp, entryID](const boost::system::error_code ec,
1891 const sdbusplus::message::unix_fd& unixfd) {
1892 if (ec.value() == EBADR)
1893 {
1894 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1895 entryID);
1896 return;
1897 }
1898 if (ec)
1899 {
1900 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1901 messages::internalError(asyncResp->res);
1902 return;
1903 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001904
Ed Tanous002d39b2022-05-31 08:59:27 -07001905 int fd = -1;
1906 fd = dup(unixfd);
1907 if (fd == -1)
1908 {
1909 messages::internalError(asyncResp->res);
1910 return;
1911 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001912
Ed Tanous002d39b2022-05-31 08:59:27 -07001913 long long int size = lseek(fd, 0, SEEK_END);
1914 if (size == -1)
1915 {
1916 messages::internalError(asyncResp->res);
1917 return;
1918 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001919
Ed Tanous002d39b2022-05-31 08:59:27 -07001920 // Arbitrary max size of 64kb
1921 constexpr int maxFileSize = 65536;
1922 if (size > maxFileSize)
1923 {
1924 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1925 << maxFileSize;
1926 messages::internalError(asyncResp->res);
1927 return;
1928 }
1929 std::vector<char> data(static_cast<size_t>(size));
1930 long long int rc = lseek(fd, 0, SEEK_SET);
1931 if (rc == -1)
1932 {
1933 messages::internalError(asyncResp->res);
1934 return;
1935 }
1936 rc = read(fd, data.data(), data.size());
1937 if ((rc == -1) || (rc != size))
1938 {
1939 messages::internalError(asyncResp->res);
1940 return;
1941 }
1942 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001943
Ed Tanous002d39b2022-05-31 08:59:27 -07001944 std::string_view strData(data.data(), data.size());
1945 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001946
Ed Tanousd9f6c622022-03-17 09:12:17 -07001947 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001948 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001949 asyncResp->res.addHeader(
1950 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001951 asyncResp->res.body() = std::move(output);
1952 },
1953 "xyz.openbmc_project.Logging",
1954 "/xyz/openbmc_project/logging/entry/" + entryID,
1955 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1956 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001957}
1958
Spencer Kub7028eb2021-10-26 15:27:35 +08001959constexpr const char* hostLoggerFolderPath = "/var/log/console";
1960
1961inline bool
1962 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1963 std::vector<std::filesystem::path>& hostLoggerFiles)
1964{
1965 std::error_code ec;
1966 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1967 if (ec)
1968 {
1969 BMCWEB_LOG_ERROR << ec.message();
1970 return false;
1971 }
1972 for (const std::filesystem::directory_entry& it : logPath)
1973 {
1974 std::string filename = it.path().filename();
1975 // Prefix of each log files is "log". Find the file and save the
1976 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07001977 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08001978 {
1979 hostLoggerFiles.emplace_back(it.path());
1980 }
1981 }
1982 // As the log files rotate, they are appended with a ".#" that is higher for
1983 // the older logs. Since we start from oldest logs, sort the name in
1984 // descending order.
1985 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1986 AlphanumLess<std::string>());
1987
1988 return true;
1989}
1990
Ed Tanous02cad962022-06-30 16:50:15 -07001991inline bool getHostLoggerEntries(
1992 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
1993 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001994{
1995 GzFileReader logFile;
1996
1997 // Go though all log files and expose host logs.
1998 for (const std::filesystem::path& it : hostLoggerFiles)
1999 {
2000 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2001 {
2002 BMCWEB_LOG_ERROR << "fail to expose host logs";
2003 return false;
2004 }
2005 }
2006 // Get lastMessage from constructor by getter
2007 std::string lastMessage = logFile.getLastMessage();
2008 if (!lastMessage.empty())
2009 {
2010 logCount++;
2011 if (logCount > skip && logCount <= (skip + top))
2012 {
2013 logEntries.push_back(lastMessage);
2014 }
2015 }
2016 return true;
2017}
2018
2019inline void fillHostLoggerEntryJson(const std::string& logEntryID,
2020 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002021 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002022{
2023 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002024 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002025 logEntryJson["@odata.id"] =
2026 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
2027 logEntryID;
2028 logEntryJson["Name"] = "Host Logger Entry";
2029 logEntryJson["Id"] = logEntryID;
2030 logEntryJson["Message"] = msg;
2031 logEntryJson["EntryType"] = "Oem";
2032 logEntryJson["Severity"] = "OK";
2033 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002034}
2035
2036inline void requestRoutesSystemHostLogger(App& app)
2037{
Ed Tanous22d268c2022-05-19 09:39:07 -07002038 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002039 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002040 .methods(boost::beast::http::verb::get)(
2041 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002042 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2043 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002044 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002045 {
2046 return;
2047 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002048 if (systemName != "system")
2049 {
2050 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2051 systemName);
2052 return;
2053 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002054 asyncResp->res.jsonValue["@odata.id"] =
2055 "/redfish/v1/Systems/system/LogServices/HostLogger";
2056 asyncResp->res.jsonValue["@odata.type"] =
2057 "#LogService.v1_1_0.LogService";
2058 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2059 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2060 asyncResp->res.jsonValue["Id"] = "HostLogger";
2061 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2062 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2063 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002064}
2065
2066inline void requestRoutesSystemHostLoggerCollection(App& app)
2067{
2068 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002069 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002070 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002071 .methods(boost::beast::http::verb::get)(
2072 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002073 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2074 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002075 query_param::QueryCapabilities capabilities = {
2076 .canDelegateTop = true,
2077 .canDelegateSkip = true,
2078 };
2079 query_param::Query delegatedQuery;
2080 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002081 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002082 {
2083 return;
2084 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002085 if (systemName != "system")
2086 {
2087 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2088 systemName);
2089 return;
2090 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002091 asyncResp->res.jsonValue["@odata.id"] =
2092 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2093 asyncResp->res.jsonValue["@odata.type"] =
2094 "#LogEntryCollection.LogEntryCollection";
2095 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2096 asyncResp->res.jsonValue["Description"] =
2097 "Collection of HostLogger Entries";
2098 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2099 logEntryArray = nlohmann::json::array();
2100 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002101
Ed Tanous002d39b2022-05-31 08:59:27 -07002102 std::vector<std::filesystem::path> hostLoggerFiles;
2103 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2104 {
2105 BMCWEB_LOG_ERROR << "fail to get host log file path";
2106 return;
2107 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002108 // If we weren't provided top and skip limits, use the defaults.
2109 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002110 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002111 size_t logCount = 0;
2112 // This vector only store the entries we want to expose that
2113 // control by skip and top.
2114 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002115 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2116 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002117 {
2118 messages::internalError(asyncResp->res);
2119 return;
2120 }
2121 // If vector is empty, that means skip value larger than total
2122 // log count
2123 if (logEntries.empty())
2124 {
2125 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2126 return;
2127 }
2128 if (!logEntries.empty())
2129 {
2130 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002131 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002132 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002133 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2134 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002135 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002136 }
2137
Ed Tanous002d39b2022-05-31 08:59:27 -07002138 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002139 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002140 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002141 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2142 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002143 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002144 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002145 }
George Liu0fda0f12021-11-16 10:06:17 +08002146 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002147}
2148
2149inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2150{
2151 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002152 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002153 .privileges(redfish::privileges::getLogEntry)
2154 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002155 [&app](const crow::Request& req,
2156 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002157 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002158 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002159 {
2160 return;
2161 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002162 if (systemName != "system")
2163 {
2164 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2165 systemName);
2166 return;
2167 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002168 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002169
Ed Tanous002d39b2022-05-31 08:59:27 -07002170 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002171
Ed Tanous002d39b2022-05-31 08:59:27 -07002172 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2173 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002174
Ed Tanous002d39b2022-05-31 08:59:27 -07002175 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002176 if (ec == std::errc::invalid_argument ||
2177 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002178 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002179 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002180 return;
2181 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002182
Ed Tanous002d39b2022-05-31 08:59:27 -07002183 std::vector<std::filesystem::path> hostLoggerFiles;
2184 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2185 {
2186 BMCWEB_LOG_ERROR << "fail to get host log file path";
2187 return;
2188 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002189
Ed Tanous002d39b2022-05-31 08:59:27 -07002190 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002191 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002192 std::vector<std::string> logEntries;
2193 // We can get specific entry by skip and top. For example, if we
2194 // want to get nth entry, we can set skip = n-1 and top = 1 to
2195 // get that entry
2196 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2197 logCount))
2198 {
2199 messages::internalError(asyncResp->res);
2200 return;
2201 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002202
Ed Tanous002d39b2022-05-31 08:59:27 -07002203 if (!logEntries.empty())
2204 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002205 nlohmann::json::object_t hostLogEntry;
2206 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2207 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002208 return;
2209 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002210
Ed Tanous002d39b2022-05-31 08:59:27 -07002211 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002212 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002213 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002214}
2215
Claire Weinanfdd26902022-03-01 14:18:25 -08002216constexpr char const* dumpManagerIface =
2217 "xyz.openbmc_project.Collection.DeleteAll";
Claire Weinandd72e872022-08-15 14:20:06 -07002218inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002219 crow::App& app, const crow::Request& req,
2220 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2221{
2222 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2223 {
2224 return;
2225 }
2226 // Collections don't include the static data added by SubRoute
2227 // because it has a duplicate entry for members
2228 asyncResp->res.jsonValue["@odata.type"] =
2229 "#LogServiceCollection.LogServiceCollection";
2230 asyncResp->res.jsonValue["@odata.id"] =
2231 "/redfish/v1/Managers/bmc/LogServices";
2232 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2233 asyncResp->res.jsonValue["Description"] =
2234 "Collection of LogServices for this Manager";
2235 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2236 logServiceArray = nlohmann::json::array();
2237
2238#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002239 nlohmann::json::object_t journal;
2240 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2241 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002242#endif
2243
2244 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2245
2246#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2247 auto respHandler =
2248 [asyncResp](
2249 const boost::system::error_code ec,
2250 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2251 if (ec)
2252 {
2253 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002254 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002255 << ec;
2256 // Assume that getting an error simply means there are no dump
2257 // LogServices. Return without adding any error response.
2258 return;
2259 }
2260
2261 nlohmann::json& logServiceArrayLocal =
2262 asyncResp->res.jsonValue["Members"];
2263
2264 for (const std::string& path : subTreePaths)
2265 {
2266 if (path == "/xyz/openbmc_project/dump/bmc")
2267 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002268 nlohmann::json::object_t member;
2269 member["@odata.id"] =
2270 "/redfish/v1/Managers/bmc/LogServices/Dump";
2271 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002272 }
2273 else if (path == "/xyz/openbmc_project/dump/faultlog")
2274 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002275 nlohmann::json::object_t member;
2276 member["@odata.id"] =
2277 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2278 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002279 }
2280 }
2281
2282 asyncResp->res.jsonValue["Members@odata.count"] =
2283 logServiceArrayLocal.size();
2284 };
2285
2286 crow::connections::systemBus->async_method_call(
2287 respHandler, "xyz.openbmc_project.ObjectMapper",
2288 "/xyz/openbmc_project/object_mapper",
2289 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2290 "/xyz/openbmc_project/dump", 0,
2291 std::array<const char*, 1>{dumpManagerIface});
2292#endif
2293}
2294
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002295inline void requestRoutesBMCLogServiceCollection(App& app)
2296{
2297 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002298 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002299 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002300 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002301}
Ed Tanous1da66f72018-07-27 16:13:37 -07002302
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002303inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002304{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002305 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002306 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002307 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002308 [&app](const crow::Request& req,
2309 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002310 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002311 {
2312 return;
2313 }
2314 asyncResp->res.jsonValue["@odata.type"] =
2315 "#LogService.v1_1_0.LogService";
2316 asyncResp->res.jsonValue["@odata.id"] =
2317 "/redfish/v1/Managers/bmc/LogServices/Journal";
2318 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2319 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2320 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2321 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302322
Ed Tanous002d39b2022-05-31 08:59:27 -07002323 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002324 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002325 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2326 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2327 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302328
Ed Tanous002d39b2022-05-31 08:59:27 -07002329 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2330 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2331 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002332}
Jason M. Billse1f26342018-07-18 12:12:00 -07002333
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002334static int
2335 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2336 sd_journal* journal,
2337 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002338{
2339 // Get the Log Entry contents
2340 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002341
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002342 std::string message;
2343 std::string_view syslogID;
2344 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2345 if (ret < 0)
2346 {
2347 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2348 << strerror(-ret);
2349 }
2350 if (!syslogID.empty())
2351 {
2352 message += std::string(syslogID) + ": ";
2353 }
2354
Ed Tanous39e77502019-03-04 17:35:53 -08002355 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002356 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002357 if (ret < 0)
2358 {
2359 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2360 return 1;
2361 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002362 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002363
2364 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002365 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002366 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002367 if (ret < 0)
2368 {
2369 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002370 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002371
2372 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002373 std::string entryTimeStr;
2374 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002375 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002376 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002377 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002378
2379 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002380 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002381 bmcJournalLogEntryJson["@odata.id"] =
2382 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2383 bmcJournalLogEntryID;
2384 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2385 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2386 bmcJournalLogEntryJson["Message"] = std::move(message);
2387 bmcJournalLogEntryJson["EntryType"] = "Oem";
2388 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2389 : severity <= 4 ? "Warning"
2390 : "OK";
2391 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2392 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002393 return 0;
2394}
2395
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002396inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002397{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002398 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002399 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002400 .methods(boost::beast::http::verb::get)(
2401 [&app](const crow::Request& req,
2402 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2403 query_param::QueryCapabilities capabilities = {
2404 .canDelegateTop = true,
2405 .canDelegateSkip = true,
2406 };
2407 query_param::Query delegatedQuery;
2408 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002409 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002410 {
2411 return;
2412 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002413
2414 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002415 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002416
Ed Tanous002d39b2022-05-31 08:59:27 -07002417 // Collections don't include the static data added by SubRoute
2418 // because it has a duplicate entry for members
2419 asyncResp->res.jsonValue["@odata.type"] =
2420 "#LogEntryCollection.LogEntryCollection";
2421 asyncResp->res.jsonValue["@odata.id"] =
2422 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2423 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2424 asyncResp->res.jsonValue["Description"] =
2425 "Collection of BMC Journal Entries";
2426 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2427 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002428
Ed Tanous002d39b2022-05-31 08:59:27 -07002429 // Go through the journal and use the timestamp to create a
2430 // unique ID for each entry
2431 sd_journal* journalTmp = nullptr;
2432 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2433 if (ret < 0)
2434 {
2435 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2436 messages::internalError(asyncResp->res);
2437 return;
2438 }
2439 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2440 journalTmp, sd_journal_close);
2441 journalTmp = nullptr;
2442 uint64_t entryCount = 0;
2443 // Reset the unique ID on the first entry
2444 bool firstEntry = true;
2445 SD_JOURNAL_FOREACH(journal.get())
2446 {
2447 entryCount++;
2448 // Handle paging using skip (number of entries to skip from
2449 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002450 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002451 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002452 continue;
2453 }
2454
2455 std::string idStr;
2456 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2457 {
2458 continue;
2459 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002460 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002461
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002462 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002463 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2464 bmcJournalLogEntry) != 0)
2465 {
George Liu0fda0f12021-11-16 10:06:17 +08002466 messages::internalError(asyncResp->res);
2467 return;
2468 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002469 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002470 }
2471 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002472 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002473 {
2474 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2475 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002476 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002477 }
George Liu0fda0f12021-11-16 10:06:17 +08002478 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002479}
Jason M. Billse1f26342018-07-18 12:12:00 -07002480
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002481inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002482{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002483 BMCWEB_ROUTE(app,
2484 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002485 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002486 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002487 [&app](const crow::Request& req,
2488 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2489 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002490 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002491 {
2492 return;
2493 }
2494 // Convert the unique ID back to a timestamp to find the entry
2495 uint64_t ts = 0;
2496 uint64_t index = 0;
2497 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2498 {
2499 return;
2500 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002501
Ed Tanous002d39b2022-05-31 08:59:27 -07002502 sd_journal* journalTmp = nullptr;
2503 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2504 if (ret < 0)
2505 {
2506 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2507 messages::internalError(asyncResp->res);
2508 return;
2509 }
2510 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2511 journalTmp, sd_journal_close);
2512 journalTmp = nullptr;
2513 // Go to the timestamp in the log and move to the entry at the
2514 // index tracking the unique ID
2515 std::string idStr;
2516 bool firstEntry = true;
2517 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2518 if (ret < 0)
2519 {
2520 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2521 << strerror(-ret);
2522 messages::internalError(asyncResp->res);
2523 return;
2524 }
2525 for (uint64_t i = 0; i <= index; i++)
2526 {
2527 sd_journal_next(journal.get());
2528 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2529 {
2530 messages::internalError(asyncResp->res);
2531 return;
2532 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002533 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002534 }
2535 // Confirm that the entry ID matches what was requested
2536 if (idStr != entryID)
2537 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002538 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002539 return;
2540 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002541
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002542 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002543 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002544 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002545 {
2546 messages::internalError(asyncResp->res);
2547 return;
2548 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002549 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002550 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002551}
2552
Claire Weinanfdd26902022-03-01 14:18:25 -08002553inline void
2554 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2555 const std::string& dumpType)
2556{
2557 std::string dumpPath;
2558 std::string overWritePolicy;
2559 bool collectDiagnosticDataSupported = false;
2560
2561 if (dumpType == "BMC")
2562 {
2563 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2564 overWritePolicy = "WrapsWhenFull";
2565 collectDiagnosticDataSupported = true;
2566 }
2567 else if (dumpType == "FaultLog")
2568 {
2569 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2570 overWritePolicy = "Unknown";
2571 collectDiagnosticDataSupported = false;
2572 }
2573 else if (dumpType == "System")
2574 {
2575 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2576 overWritePolicy = "WrapsWhenFull";
2577 collectDiagnosticDataSupported = true;
2578 }
2579 else
2580 {
2581 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2582 << dumpType;
2583 messages::internalError(asyncResp->res);
2584 return;
2585 }
2586
2587 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2588 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2589 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2590 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2591 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2592 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2593
2594 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002595 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002596 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2597 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2598 redfishDateTimeOffset.second;
2599
2600 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2601 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2602 dumpPath + "/Actions/LogService.ClearLog";
2603
2604 if (collectDiagnosticDataSupported)
2605 {
2606 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2607 ["target"] =
2608 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2609 }
2610}
2611
2612inline void handleLogServicesDumpServiceGet(
2613 crow::App& app, const std::string& dumpType, const crow::Request& req,
2614 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2615{
2616 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2617 {
2618 return;
2619 }
2620 getDumpServiceInfo(asyncResp, dumpType);
2621}
2622
Ed Tanous22d268c2022-05-19 09:39:07 -07002623inline void handleLogServicesDumpServiceComputerSystemGet(
2624 crow::App& app, const crow::Request& req,
2625 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2626 const std::string& chassisId)
2627{
2628 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2629 {
2630 return;
2631 }
2632 if (chassisId != "system")
2633 {
2634 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2635 return;
2636 }
2637 getDumpServiceInfo(asyncResp, "System");
2638}
2639
Claire Weinanfdd26902022-03-01 14:18:25 -08002640inline void handleLogServicesDumpEntriesCollectionGet(
2641 crow::App& app, const std::string& dumpType, const crow::Request& req,
2642 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2643{
2644 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2645 {
2646 return;
2647 }
2648 getDumpEntryCollection(asyncResp, dumpType);
2649}
2650
Ed Tanous22d268c2022-05-19 09:39:07 -07002651inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2652 crow::App& app, const crow::Request& req,
2653 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2654 const std::string& chassisId)
2655{
2656 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2657 {
2658 return;
2659 }
2660 if (chassisId != "system")
2661 {
2662 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2663 return;
2664 }
2665 getDumpEntryCollection(asyncResp, "System");
2666}
2667
Claire Weinanfdd26902022-03-01 14:18:25 -08002668inline void handleLogServicesDumpEntryGet(
2669 crow::App& app, const std::string& dumpType, const crow::Request& req,
2670 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2671 const std::string& dumpId)
2672{
2673 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2674 {
2675 return;
2676 }
2677 getDumpEntryById(asyncResp, dumpId, dumpType);
2678}
Ed Tanous22d268c2022-05-19 09:39:07 -07002679inline void handleLogServicesDumpEntryComputerSystemGet(
2680 crow::App& app, const crow::Request& req,
2681 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2682 const std::string& chassisId, const std::string& dumpId)
2683{
2684 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2685 {
2686 return;
2687 }
2688 if (chassisId != "system")
2689 {
2690 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2691 return;
2692 }
2693 getDumpEntryById(asyncResp, dumpId, "System");
2694}
Claire Weinanfdd26902022-03-01 14:18:25 -08002695
2696inline void handleLogServicesDumpEntryDelete(
2697 crow::App& app, const std::string& dumpType, const crow::Request& req,
2698 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2699 const std::string& dumpId)
2700{
2701 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2702 {
2703 return;
2704 }
2705 deleteDumpEntry(asyncResp, dumpId, dumpType);
2706}
2707
Ed Tanous22d268c2022-05-19 09:39:07 -07002708inline void handleLogServicesDumpEntryComputerSystemDelete(
2709 crow::App& app, const crow::Request& req,
2710 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2711 const std::string& chassisId, const std::string& dumpId)
2712{
2713 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2714 {
2715 return;
2716 }
2717 if (chassisId != "system")
2718 {
2719 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2720 return;
2721 }
2722 deleteDumpEntry(asyncResp, dumpId, "System");
2723}
2724
Claire Weinanfdd26902022-03-01 14:18:25 -08002725inline void handleLogServicesDumpCollectDiagnosticDataPost(
2726 crow::App& app, const std::string& dumpType, const crow::Request& req,
2727 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2728{
2729 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2730 {
2731 return;
2732 }
2733 createDump(asyncResp, req, dumpType);
2734}
2735
Ed Tanous22d268c2022-05-19 09:39:07 -07002736inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2737 crow::App& app, const crow::Request& req,
2738 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2739 const std::string& chassisId)
2740{
2741 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2742 {
2743 return;
2744 }
2745 if (chassisId != "system")
2746 {
2747 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2748 return;
2749 }
2750 createDump(asyncResp, req, "System");
2751}
2752
Claire Weinanfdd26902022-03-01 14:18:25 -08002753inline void handleLogServicesDumpClearLogPost(
2754 crow::App& app, const std::string& dumpType, const crow::Request& req,
2755 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2756{
2757 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2758 {
2759 return;
2760 }
2761 clearDump(asyncResp, dumpType);
2762}
2763
Ed Tanous22d268c2022-05-19 09:39:07 -07002764inline void handleLogServicesDumpClearLogComputerSystemPost(
2765 crow::App& app, const crow::Request& req,
2766 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2767 const std::string& chassisId)
2768{
2769 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2770 {
2771 return;
2772 }
2773 if (chassisId != "system")
2774 {
2775 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2776 return;
2777 }
2778 clearDump(asyncResp, "System");
2779}
2780
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002781inline void requestRoutesBMCDumpService(App& app)
2782{
2783 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002784 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002785 .methods(boost::beast::http::verb::get)(std::bind_front(
2786 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002787}
2788
2789inline void requestRoutesBMCDumpEntryCollection(App& app)
2790{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002791 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002792 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002793 .methods(boost::beast::http::verb::get)(std::bind_front(
2794 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002795}
2796
2797inline void requestRoutesBMCDumpEntry(App& app)
2798{
2799 BMCWEB_ROUTE(app,
2800 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002801 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002802 .methods(boost::beast::http::verb::get)(std::bind_front(
2803 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2804
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002805 BMCWEB_ROUTE(app,
2806 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002807 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002808 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2809 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002810}
2811
2812inline void requestRoutesBMCDumpCreate(App& app)
2813{
George Liu0fda0f12021-11-16 10:06:17 +08002814 BMCWEB_ROUTE(
2815 app,
2816 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002817 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002818 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002819 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2820 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002821}
2822
2823inline void requestRoutesBMCDumpClear(App& app)
2824{
George Liu0fda0f12021-11-16 10:06:17 +08002825 BMCWEB_ROUTE(
2826 app,
2827 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002828 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002829 .methods(boost::beast::http::verb::post)(std::bind_front(
2830 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2831}
2832
2833inline void requestRoutesFaultLogDumpService(App& app)
2834{
2835 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2836 .privileges(redfish::privileges::getLogService)
2837 .methods(boost::beast::http::verb::get)(std::bind_front(
2838 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2839}
2840
2841inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2842{
2843 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2844 .privileges(redfish::privileges::getLogEntryCollection)
2845 .methods(boost::beast::http::verb::get)(
2846 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2847 std::ref(app), "FaultLog"));
2848}
2849
2850inline void requestRoutesFaultLogDumpEntry(App& app)
2851{
2852 BMCWEB_ROUTE(app,
2853 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2854 .privileges(redfish::privileges::getLogEntry)
2855 .methods(boost::beast::http::verb::get)(std::bind_front(
2856 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2857
2858 BMCWEB_ROUTE(app,
2859 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2860 .privileges(redfish::privileges::deleteLogEntry)
2861 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2862 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2863}
2864
2865inline void requestRoutesFaultLogDumpClear(App& app)
2866{
2867 BMCWEB_ROUTE(
2868 app,
2869 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2870 .privileges(redfish::privileges::postLogService)
2871 .methods(boost::beast::http::verb::post)(std::bind_front(
2872 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002873}
2874
2875inline void requestRoutesSystemDumpService(App& app)
2876{
Ed Tanous22d268c2022-05-19 09:39:07 -07002877 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002878 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002879 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002880 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002881}
2882
2883inline void requestRoutesSystemDumpEntryCollection(App& app)
2884{
Ed Tanous22d268c2022-05-19 09:39:07 -07002885 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002886 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002887 .methods(boost::beast::http::verb::get)(std::bind_front(
2888 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2889 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002890}
2891
2892inline void requestRoutesSystemDumpEntry(App& app)
2893{
2894 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002895 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002896 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002897 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002898 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002899
2900 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002901 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002902 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002903 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002904 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002905}
2906
2907inline void requestRoutesSystemDumpCreate(App& app)
2908{
George Liu0fda0f12021-11-16 10:06:17 +08002909 BMCWEB_ROUTE(
2910 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002911 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002912 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002913 .methods(boost::beast::http::verb::post)(std::bind_front(
2914 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2915 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002916}
2917
2918inline void requestRoutesSystemDumpClear(App& app)
2919{
George Liu0fda0f12021-11-16 10:06:17 +08002920 BMCWEB_ROUTE(
2921 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002922 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002923 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002924 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002925 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002926}
2927
2928inline void requestRoutesCrashdumpService(App& app)
2929{
2930 // Note: Deviated from redfish privilege registry for GET & HEAD
2931 // method for security reasons.
2932 /**
2933 * Functions triggers appropriate requests on DBus
2934 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002935 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002936 // This is incorrect, should be:
2937 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002938 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002939 .methods(boost::beast::http::verb::get)(
2940 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002941 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2942 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002943 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002944 {
2945 return;
2946 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002947 if (systemName != "system")
2948 {
2949 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2950 systemName);
2951 return;
2952 }
2953
Ed Tanous002d39b2022-05-31 08:59:27 -07002954 // Copy over the static data to include the entries added by
2955 // SubRoute
2956 asyncResp->res.jsonValue["@odata.id"] =
2957 "/redfish/v1/Systems/system/LogServices/Crashdump";
2958 asyncResp->res.jsonValue["@odata.type"] =
2959 "#LogService.v1_2_0.LogService";
2960 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2961 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2962 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2963 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2964 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302965
Ed Tanous002d39b2022-05-31 08:59:27 -07002966 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002967 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002968 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2969 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2970 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302971
Ed Tanous002d39b2022-05-31 08:59:27 -07002972 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2973 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2974 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2975 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2976 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2977 ["target"] =
2978 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002979 });
2980}
2981
2982void inline requestRoutesCrashdumpClear(App& app)
2983{
George Liu0fda0f12021-11-16 10:06:17 +08002984 BMCWEB_ROUTE(
2985 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002986 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002987 // This is incorrect, should be:
2988 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002989 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002990 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002991 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002992 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2993 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002994 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002995 {
2996 return;
2997 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002998 if (systemName != "system")
2999 {
3000 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3001 systemName);
3002 return;
3003 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003004 crow::connections::systemBus->async_method_call(
3005 [asyncResp](const boost::system::error_code ec,
3006 const std::string&) {
3007 if (ec)
3008 {
3009 messages::internalError(asyncResp->res);
3010 return;
3011 }
3012 messages::success(asyncResp->res);
3013 },
3014 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
3015 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003016}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003017
zhanghch058d1b46d2021-04-01 11:18:24 +08003018static void
3019 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3020 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003021{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003022 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003023 [asyncResp, logID,
3024 &logEntryJson](const boost::system::error_code ec,
3025 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003026 if (ec)
3027 {
3028 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3029 if (ec.value() ==
3030 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003031 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003032 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003033 }
3034 else
3035 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003036 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003037 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003038 return;
3039 }
3040
3041 std::string timestamp{};
3042 std::string filename{};
3043 std::string logfile{};
3044 parseCrashdumpParameters(params, filename, timestamp, logfile);
3045
3046 if (filename.empty() || timestamp.empty())
3047 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003048 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003049 return;
3050 }
3051
3052 std::string crashdumpURI =
3053 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3054 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003055 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003056 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003057 logEntry["@odata.id"] =
3058 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
3059 logEntry["Name"] = "CPU Crashdump";
3060 logEntry["Id"] = logID;
3061 logEntry["EntryType"] = "Oem";
3062 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3063 logEntry["DiagnosticDataType"] = "OEM";
3064 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3065 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003066
3067 // If logEntryJson references an array of LogEntry resources
3068 // ('Members' list), then push this as a new entry, otherwise set it
3069 // directly
3070 if (logEntryJson.is_array())
3071 {
3072 logEntryJson.push_back(logEntry);
3073 asyncResp->res.jsonValue["Members@odata.count"] =
3074 logEntryJson.size();
3075 }
3076 else
3077 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003078 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003079 }
3080 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003081 sdbusplus::asio::getAllProperties(
3082 *crow::connections::systemBus, crashdumpObject,
3083 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3084 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003085}
3086
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003087inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003088{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003089 // Note: Deviated from redfish privilege registry for GET & HEAD
3090 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003091 /**
3092 * Functions triggers appropriate requests on DBus
3093 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003094 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003095 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003096 // This is incorrect, should be.
3097 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003098 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003099 .methods(boost::beast::http::verb::get)(
3100 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003101 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3102 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003103 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003104 {
3105 return;
3106 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003107 if (systemName != "system")
3108 {
3109 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3110 systemName);
3111 return;
3112 }
3113
Ed Tanous002d39b2022-05-31 08:59:27 -07003114 crow::connections::systemBus->async_method_call(
3115 [asyncResp](const boost::system::error_code ec,
3116 const std::vector<std::string>& resp) {
3117 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003118 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003119 if (ec.value() !=
3120 boost::system::errc::no_such_file_or_directory)
3121 {
3122 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3123 << ec.message();
3124 messages::internalError(asyncResp->res);
3125 return;
3126 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003127 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003128 asyncResp->res.jsonValue["@odata.type"] =
3129 "#LogEntryCollection.LogEntryCollection";
3130 asyncResp->res.jsonValue["@odata.id"] =
3131 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3132 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3133 asyncResp->res.jsonValue["Description"] =
3134 "Collection of Crashdump Entries";
3135 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3136 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003137
Ed Tanous002d39b2022-05-31 08:59:27 -07003138 for (const std::string& path : resp)
3139 {
3140 const sdbusplus::message::object_path objPath(path);
3141 // Get the log ID
3142 std::string logID = objPath.filename();
3143 if (logID.empty())
3144 {
3145 continue;
3146 }
3147 // Add the log entry to the array
3148 logCrashdumpEntry(asyncResp, logID,
3149 asyncResp->res.jsonValue["Members"]);
3150 }
3151 },
3152 "xyz.openbmc_project.ObjectMapper",
3153 "/xyz/openbmc_project/object_mapper",
3154 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
3155 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003156 });
3157}
Ed Tanous1da66f72018-07-27 16:13:37 -07003158
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003159inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003160{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003161 // Note: Deviated from redfish privilege registry for GET & HEAD
3162 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003163
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003164 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003165 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003166 // this is incorrect, should be
3167 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003168 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003169 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003170 [&app](const crow::Request& req,
3171 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003172 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003173 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003174 {
3175 return;
3176 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003177 if (systemName != "system")
3178 {
3179 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3180 systemName);
3181 ;
3182 return;
3183 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003184 const std::string& logID = param;
3185 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3186 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003187}
Ed Tanous1da66f72018-07-27 16:13:37 -07003188
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003189inline void requestRoutesCrashdumpFile(App& app)
3190{
3191 // Note: Deviated from redfish privilege registry for GET & HEAD
3192 // method for security reasons.
3193 BMCWEB_ROUTE(
3194 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003195 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003196 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003197 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003198 [](const crow::Request& req,
3199 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003200 const std::string& systemName, const std::string& logID,
3201 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003202 // Do not call getRedfishRoute here since the crashdump file is not a
3203 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003204
3205 if (systemName != "system")
3206 {
3207 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3208 systemName);
3209 ;
3210 return;
3211 }
3212
Ed Tanous002d39b2022-05-31 08:59:27 -07003213 auto getStoredLogCallback =
3214 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3215 const boost::system::error_code ec,
3216 const std::vector<
3217 std::pair<std::string, dbus::utility::DbusVariantType>>&
3218 resp) {
3219 if (ec)
3220 {
3221 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3222 messages::internalError(asyncResp->res);
3223 return;
3224 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003225
Ed Tanous002d39b2022-05-31 08:59:27 -07003226 std::string dbusFilename{};
3227 std::string dbusTimestamp{};
3228 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003229
Ed Tanous002d39b2022-05-31 08:59:27 -07003230 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3231 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003232
Ed Tanous002d39b2022-05-31 08:59:27 -07003233 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3234 dbusFilepath.empty())
3235 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003236 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003237 return;
3238 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003239
Ed Tanous002d39b2022-05-31 08:59:27 -07003240 // Verify the file name parameter is correct
3241 if (fileName != dbusFilename)
3242 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003243 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003244 return;
3245 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003246
Ed Tanous002d39b2022-05-31 08:59:27 -07003247 if (!std::filesystem::exists(dbusFilepath))
3248 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003249 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003250 return;
3251 }
3252 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3253 asyncResp->res.body() =
3254 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003255
Ed Tanous002d39b2022-05-31 08:59:27 -07003256 // Configure this to be a file download when accessed
3257 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003258 asyncResp->res.addHeader(
3259 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003260 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003261 sdbusplus::asio::getAllProperties(
3262 *crow::connections::systemBus, crashdumpObject,
3263 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3264 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003265 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003266}
3267
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003268enum class OEMDiagnosticType
3269{
3270 onDemand,
3271 telemetry,
3272 invalid,
3273};
3274
Ed Tanousf7725d72022-03-07 12:46:00 -08003275inline OEMDiagnosticType
3276 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003277{
3278 if (oemDiagStr == "OnDemand")
3279 {
3280 return OEMDiagnosticType::onDemand;
3281 }
3282 if (oemDiagStr == "Telemetry")
3283 {
3284 return OEMDiagnosticType::telemetry;
3285 }
3286
3287 return OEMDiagnosticType::invalid;
3288}
3289
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003290inline void requestRoutesCrashdumpCollect(App& app)
3291{
3292 // Note: Deviated from redfish privilege registry for GET & HEAD
3293 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003294 BMCWEB_ROUTE(
3295 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003296 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003297 // The below is incorrect; Should be ConfigureManager
3298 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003299 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003300 .methods(boost::beast::http::verb::post)(
3301 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3303 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003304 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003305 {
3306 return;
3307 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003308
3309 if (systemName != "system")
3310 {
3311 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3312 systemName);
3313 ;
3314 return;
3315 }
3316
Ed Tanous002d39b2022-05-31 08:59:27 -07003317 std::string diagnosticDataType;
3318 std::string oemDiagnosticDataType;
3319 if (!redfish::json_util::readJsonAction(
3320 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3321 "OEMDiagnosticDataType", oemDiagnosticDataType))
3322 {
3323 return;
3324 }
3325
3326 if (diagnosticDataType != "OEM")
3327 {
3328 BMCWEB_LOG_ERROR
3329 << "Only OEM DiagnosticDataType supported for Crashdump";
3330 messages::actionParameterValueFormatError(
3331 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3332 "CollectDiagnosticData");
3333 return;
3334 }
3335
3336 OEMDiagnosticType oemDiagType =
3337 getOEMDiagnosticType(oemDiagnosticDataType);
3338
3339 std::string iface;
3340 std::string method;
3341 std::string taskMatchStr;
3342 if (oemDiagType == OEMDiagnosticType::onDemand)
3343 {
3344 iface = crashdumpOnDemandInterface;
3345 method = "GenerateOnDemandLog";
3346 taskMatchStr = "type='signal',"
3347 "interface='org.freedesktop.DBus.Properties',"
3348 "member='PropertiesChanged',"
3349 "arg0namespace='com.intel.crashdump'";
3350 }
3351 else if (oemDiagType == OEMDiagnosticType::telemetry)
3352 {
3353 iface = crashdumpTelemetryInterface;
3354 method = "GenerateTelemetryLog";
3355 taskMatchStr = "type='signal',"
3356 "interface='org.freedesktop.DBus.Properties',"
3357 "member='PropertiesChanged',"
3358 "arg0namespace='com.intel.crashdump'";
3359 }
3360 else
3361 {
3362 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3363 << oemDiagnosticDataType;
3364 messages::actionParameterValueFormatError(
3365 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3366 "CollectDiagnosticData");
3367 return;
3368 }
3369
3370 auto collectCrashdumpCallback =
3371 [asyncResp, payload(task::Payload(req)),
3372 taskMatchStr](const boost::system::error_code ec,
3373 const std::string&) mutable {
3374 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003375 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003376 if (ec.value() == boost::system::errc::operation_not_supported)
3377 {
3378 messages::resourceInStandby(asyncResp->res);
3379 }
3380 else if (ec.value() ==
3381 boost::system::errc::device_or_resource_busy)
3382 {
3383 messages::serviceTemporarilyUnavailable(asyncResp->res,
3384 "60");
3385 }
3386 else
3387 {
3388 messages::internalError(asyncResp->res);
3389 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003390 return;
3391 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003392 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003393 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003394 const std::shared_ptr<task::TaskData>& taskData) {
3395 if (!err)
3396 {
3397 taskData->messages.emplace_back(messages::taskCompletedOK(
3398 std::to_string(taskData->index)));
3399 taskData->state = "Completed";
3400 }
3401 return task::completed;
3402 },
3403 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003404
Ed Tanous002d39b2022-05-31 08:59:27 -07003405 task->startTimer(std::chrono::minutes(5));
3406 task->populateResp(asyncResp->res);
3407 task->payload.emplace(std::move(payload));
3408 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003409
Ed Tanous002d39b2022-05-31 08:59:27 -07003410 crow::connections::systemBus->async_method_call(
3411 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3412 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003413 });
3414}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003415
Andrew Geisslercb92c032018-08-17 07:56:14 -07003416/**
3417 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3418 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003419inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003420{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003421 /**
3422 * Function handles POST method request.
3423 * The Clear Log actions does not require any parameter.The action deletes
3424 * all entries found in the Entries collection for this Log Service.
3425 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003426
George Liu0fda0f12021-11-16 10:06:17 +08003427 BMCWEB_ROUTE(
3428 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003429 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003430 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003431 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003432 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003433 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3434 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003435 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003436 {
3437 return;
3438 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003439 if (systemName != "system")
3440 {
3441 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3442 systemName);
3443 ;
3444 return;
3445 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003446 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003447
Ed Tanous002d39b2022-05-31 08:59:27 -07003448 // Process response from Logging service.
3449 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3450 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3451 if (ec)
3452 {
3453 // TODO Handle for specific error code
3454 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3455 asyncResp->res.result(
3456 boost::beast::http::status::internal_server_error);
3457 return;
3458 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003459
Ed Tanous002d39b2022-05-31 08:59:27 -07003460 asyncResp->res.result(boost::beast::http::status::no_content);
3461 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003462
Ed Tanous002d39b2022-05-31 08:59:27 -07003463 // Make call to Logging service to request Clear Log
3464 crow::connections::systemBus->async_method_call(
3465 respHandler, "xyz.openbmc_project.Logging",
3466 "/xyz/openbmc_project/logging",
3467 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3468 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003469}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003470
3471/****************************************************
3472 * Redfish PostCode interfaces
3473 * using DBUS interface: getPostCodesTS
3474 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003475inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003476{
Ed Tanous22d268c2022-05-19 09:39:07 -07003477 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003478 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003479 .methods(boost::beast::http::verb::get)(
3480 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003481 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3482 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003483 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003484 {
3485 return;
3486 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003487 if (systemName != "system")
3488 {
3489 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3490 systemName);
3491 ;
3492 return;
3493 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003494 asyncResp->res.jsonValue["@odata.id"] =
3495 "/redfish/v1/Systems/system/LogServices/PostCodes";
3496 asyncResp->res.jsonValue["@odata.type"] =
3497 "#LogService.v1_1_0.LogService";
3498 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3499 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3500 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3501 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3502 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3503 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303504
Ed Tanous002d39b2022-05-31 08:59:27 -07003505 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003506 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003507 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3508 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3509 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303510
Ed Tanous002d39b2022-05-31 08:59:27 -07003511 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3512 {"target",
3513 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003514 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003515}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003516
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003517inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003518{
George Liu0fda0f12021-11-16 10:06:17 +08003519 BMCWEB_ROUTE(
3520 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003521 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003522 // The following privilege is incorrect; It should be ConfigureManager
3523 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003524 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003525 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003526 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003527 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3528 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003529 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003530 {
3531 return;
3532 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003533 if (systemName != "system")
3534 {
3535 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3536 systemName);
3537 ;
3538 return;
3539 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003540 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003541
Ed Tanous002d39b2022-05-31 08:59:27 -07003542 // Make call to post-code service to request clear all
3543 crow::connections::systemBus->async_method_call(
3544 [asyncResp](const boost::system::error_code ec) {
3545 if (ec)
3546 {
3547 // TODO Handle for specific error code
3548 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3549 << ec;
3550 asyncResp->res.result(
3551 boost::beast::http::status::internal_server_error);
3552 messages::internalError(asyncResp->res);
3553 return;
3554 }
3555 },
3556 "xyz.openbmc_project.State.Boot.PostCode0",
3557 "/xyz/openbmc_project/State/Boot/PostCode0",
3558 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3559 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003560}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003561
3562static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003563 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303564 const boost::container::flat_map<
3565 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003566 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3567 const uint64_t skip = 0, const uint64_t top = 0)
3568{
3569 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003570 const registries::Message* message =
3571 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003572
3573 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003574 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003575
3576 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303577 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3578 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003579 {
3580 currentCodeIndex++;
3581 std::string postcodeEntryID =
3582 "B" + std::to_string(bootIndex) + "-" +
3583 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3584
3585 uint64_t usecSinceEpoch = code.first;
3586 uint64_t usTimeOffset = 0;
3587
3588 if (1 == currentCodeIndex)
3589 { // already incremented
3590 firstCodeTimeUs = code.first;
3591 }
3592 else
3593 {
3594 usTimeOffset = code.first - firstCodeTimeUs;
3595 }
3596
3597 // skip if no specific codeIndex is specified and currentCodeIndex does
3598 // not fall between top and skip
3599 if ((codeIndex == 0) &&
3600 (currentCodeIndex <= skip || currentCodeIndex > top))
3601 {
3602 continue;
3603 }
3604
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003605 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003606 // currentIndex
3607 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3608 {
3609 // This is done for simplicity. 1st entry is needed to calculate
3610 // time offset. To improve efficiency, one can get to the entry
3611 // directly (possibly with flatmap's nth method)
3612 continue;
3613 }
3614
3615 // currentCodeIndex is within top and skip or equal to specified code
3616 // index
3617
3618 // Get the Created time from the timestamp
3619 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003620 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003621 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003622
3623 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3624 std::ostringstream hexCode;
3625 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303626 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003627 std::ostringstream timeOffsetStr;
3628 // Set Fixed -Point Notation
3629 timeOffsetStr << std::fixed;
3630 // Set precision to 4 digits
3631 timeOffsetStr << std::setprecision(4);
3632 // Add double to stream
3633 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3634 std::vector<std::string> messageArgs = {
3635 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3636
3637 // Get MessageArgs template from message registry
3638 std::string msg;
3639 if (message != nullptr)
3640 {
3641 msg = message->message;
3642
3643 // fill in this post code value
3644 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003645 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003646 {
3647 std::string argStr = "%" + std::to_string(++i);
3648 size_t argPos = msg.find(argStr);
3649 if (argPos != std::string::npos)
3650 {
3651 msg.replace(argPos, argStr.length(), messageArg);
3652 }
3653 }
3654 }
3655
Tim Leed4342a92020-04-27 11:47:58 +08003656 // Get Severity template from message registry
3657 std::string severity;
3658 if (message != nullptr)
3659 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003660 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003661 }
3662
ZhikuiRena3316fc2020-01-29 14:58:08 -08003663 // add to AsyncResp
3664 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003665 nlohmann::json& bmcLogEntry = logEntryArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05003666 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003667 bmcLogEntry["@odata.id"] =
3668 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3669 postcodeEntryID;
3670 bmcLogEntry["Name"] = "POST Code Log Entry";
3671 bmcLogEntry["Id"] = postcodeEntryID;
3672 bmcLogEntry["Message"] = std::move(msg);
3673 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3674 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3675 bmcLogEntry["EntryType"] = "Event";
3676 bmcLogEntry["Severity"] = std::move(severity);
3677 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003678 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3679 {
3680 bmcLogEntry["AdditionalDataURI"] =
3681 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3682 postcodeEntryID + "/attachment";
3683 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003684 }
3685}
3686
zhanghch058d1b46d2021-04-01 11:18:24 +08003687static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003688 const uint16_t bootIndex,
3689 const uint64_t codeIndex)
3690{
3691 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303692 [aResp, bootIndex,
3693 codeIndex](const boost::system::error_code ec,
3694 const boost::container::flat_map<
3695 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3696 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003697 if (ec)
3698 {
3699 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3700 messages::internalError(aResp->res);
3701 return;
3702 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003703
Ed Tanous002d39b2022-05-31 08:59:27 -07003704 // skip the empty postcode boots
3705 if (postcode.empty())
3706 {
3707 return;
3708 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003709
Ed Tanous002d39b2022-05-31 08:59:27 -07003710 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003711
Ed Tanous002d39b2022-05-31 08:59:27 -07003712 aResp->res.jsonValue["Members@odata.count"] =
3713 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003714 },
Jonathan Doman15124762021-01-07 17:54:17 -08003715 "xyz.openbmc_project.State.Boot.PostCode0",
3716 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003717 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3718 bootIndex);
3719}
3720
zhanghch058d1b46d2021-04-01 11:18:24 +08003721static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003722 const uint16_t bootIndex,
3723 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003724 const uint64_t entryCount, size_t skip,
3725 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003726{
3727 crow::connections::systemBus->async_method_call(
3728 [aResp, bootIndex, bootCount, entryCount, skip,
3729 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303730 const boost::container::flat_map<
3731 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3732 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003733 if (ec)
3734 {
3735 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3736 messages::internalError(aResp->res);
3737 return;
3738 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003739
Ed Tanous002d39b2022-05-31 08:59:27 -07003740 uint64_t endCount = entryCount;
3741 if (!postcode.empty())
3742 {
3743 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003744 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003745 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003746 uint64_t thisBootSkip =
3747 std::max(static_cast<uint64_t>(skip), entryCount) -
3748 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003749 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003750 std::min(static_cast<uint64_t>(top + skip), endCount) -
3751 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003752
3753 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3754 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003755 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003756 aResp->res.jsonValue["Members@odata.count"] = endCount;
3757 }
3758
3759 // continue to previous bootIndex
3760 if (bootIndex < bootCount)
3761 {
3762 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3763 bootCount, endCount, skip, top);
3764 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003765 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003766 {
3767 aResp->res.jsonValue["Members@odata.nextLink"] =
3768 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3769 std::to_string(skip + top);
3770 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003771 },
Jonathan Doman15124762021-01-07 17:54:17 -08003772 "xyz.openbmc_project.State.Boot.PostCode0",
3773 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003774 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3775 bootIndex);
3776}
3777
zhanghch058d1b46d2021-04-01 11:18:24 +08003778static void
3779 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003780 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003781{
3782 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003783 sdbusplus::asio::getProperty<uint16_t>(
3784 *crow::connections::systemBus,
3785 "xyz.openbmc_project.State.Boot.PostCode0",
3786 "/xyz/openbmc_project/State/Boot/PostCode0",
3787 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3788 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3789 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003790 if (ec)
3791 {
3792 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3793 messages::internalError(aResp->res);
3794 return;
3795 }
3796 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003797 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003798}
3799
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003800inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003801{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003802 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003803 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003804 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003805 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003806 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003807 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3808 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003809 query_param::QueryCapabilities capabilities = {
3810 .canDelegateTop = true,
3811 .canDelegateSkip = true,
3812 };
3813 query_param::Query delegatedQuery;
3814 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003815 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003816 {
3817 return;
3818 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003819
3820 if (systemName != "system")
3821 {
3822 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3823 systemName);
3824 ;
3825 return;
3826 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003827 asyncResp->res.jsonValue["@odata.type"] =
3828 "#LogEntryCollection.LogEntryCollection";
3829 asyncResp->res.jsonValue["@odata.id"] =
3830 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3831 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3832 asyncResp->res.jsonValue["Description"] =
3833 "Collection of POST Code Log Entries";
3834 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3835 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003836 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003837 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003838 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003839 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003840}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003841
George Liu647b3cd2021-07-05 12:43:56 +08003842/**
3843 * @brief Parse post code ID and get the current value and index value
3844 * eg: postCodeID=B1-2, currentValue=1, index=2
3845 *
3846 * @param[in] postCodeID Post Code ID
3847 * @param[out] currentValue Current value
3848 * @param[out] index Index value
3849 *
3850 * @return bool true if the parsing is successful, false the parsing fails
3851 */
3852inline static bool parsePostCode(const std::string& postCodeID,
3853 uint64_t& currentValue, uint16_t& index)
3854{
3855 std::vector<std::string> split;
3856 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3857 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3858 {
3859 return false;
3860 }
3861
Ed Tanousca45aa32022-01-07 09:28:45 -08003862 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003863 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003864 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003865 const char* end = split[0].data() + split[0].size();
3866 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3867
3868 if (ptrIndex != end || ecIndex != std::errc())
3869 {
3870 return false;
3871 }
3872
3873 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003874
3875 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003876 end = split[1].data() + split[1].size();
3877 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003878
Tony Lee517d9a52022-06-28 15:41:23 +08003879 return ptrValue == end && ecValue == std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003880}
3881
3882inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3883{
George Liu0fda0f12021-11-16 10:06:17 +08003884 BMCWEB_ROUTE(
3885 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003886 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003887 .privileges(redfish::privileges::getLogEntry)
3888 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003889 [&app](const crow::Request& req,
3890 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003891 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003892 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003893 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003894 {
3895 return;
3896 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003897 if (http_helpers::isContentTypeAllowed(
3898 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003899 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003900 {
3901 asyncResp->res.result(boost::beast::http::status::bad_request);
3902 return;
3903 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003904 if (systemName != "system")
3905 {
3906 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3907 systemName);
3908 ;
3909 return;
3910 }
George Liu647b3cd2021-07-05 12:43:56 +08003911
Ed Tanous002d39b2022-05-31 08:59:27 -07003912 uint64_t currentValue = 0;
3913 uint16_t index = 0;
3914 if (!parsePostCode(postCodeID, currentValue, index))
3915 {
3916 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3917 return;
3918 }
George Liu647b3cd2021-07-05 12:43:56 +08003919
Ed Tanous002d39b2022-05-31 08:59:27 -07003920 crow::connections::systemBus->async_method_call(
3921 [asyncResp, postCodeID, currentValue](
3922 const boost::system::error_code ec,
3923 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3924 postcodes) {
3925 if (ec.value() == EBADR)
3926 {
3927 messages::resourceNotFound(asyncResp->res, "LogEntry",
3928 postCodeID);
3929 return;
3930 }
3931 if (ec)
3932 {
3933 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3934 messages::internalError(asyncResp->res);
3935 return;
3936 }
George Liu647b3cd2021-07-05 12:43:56 +08003937
Ed Tanous002d39b2022-05-31 08:59:27 -07003938 size_t value = static_cast<size_t>(currentValue) - 1;
3939 if (value == std::string::npos || postcodes.size() < currentValue)
3940 {
3941 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3942 messages::resourceNotFound(asyncResp->res, "LogEntry",
3943 postCodeID);
3944 return;
3945 }
George Liu647b3cd2021-07-05 12:43:56 +08003946
Ed Tanous002d39b2022-05-31 08:59:27 -07003947 const auto& [tID, c] = postcodes[value];
3948 if (c.empty())
3949 {
3950 BMCWEB_LOG_INFO << "No found post code data";
3951 messages::resourceNotFound(asyncResp->res, "LogEntry",
3952 postCodeID);
3953 return;
3954 }
3955 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3956 const char* d = reinterpret_cast<const char*>(c.data());
3957 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003958
Ed Tanousd9f6c622022-03-17 09:12:17 -07003959 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07003960 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07003961 asyncResp->res.addHeader(
3962 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07003963 asyncResp->res.body() = crow::utility::base64encode(strData);
3964 },
3965 "xyz.openbmc_project.State.Boot.PostCode0",
3966 "/xyz/openbmc_project/State/Boot/PostCode0",
3967 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3968 });
George Liu647b3cd2021-07-05 12:43:56 +08003969}
3970
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003971inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003972{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003973 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003974 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003975 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003976 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003977 [&app](const crow::Request& req,
3978 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003979 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003980 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003981 {
3982 return;
3983 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003984 if (systemName != "system")
3985 {
3986 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3987 systemName);
3988 return;
3989 }
3990
Ed Tanous002d39b2022-05-31 08:59:27 -07003991 uint16_t bootIndex = 0;
3992 uint64_t codeIndex = 0;
3993 if (!parsePostCode(targetID, codeIndex, bootIndex))
3994 {
3995 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003996 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003997 return;
3998 }
3999 if (bootIndex == 0 || codeIndex == 0)
4000 {
4001 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
4002 << targetID;
4003 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08004004
Vijay Lobo9c11a172021-10-07 16:53:16 -05004005 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07004006 asyncResp->res.jsonValue["@odata.id"] =
4007 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
4008 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
4009 asyncResp->res.jsonValue["Description"] =
4010 "Collection of POST Code Log Entries";
4011 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
4012 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08004013
Ed Tanous002d39b2022-05-31 08:59:27 -07004014 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
4015 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004016}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004017
Ed Tanous1da66f72018-07-27 16:13:37 -07004018} // namespace redfish