blob: 307f2e2caf67f82cd570d29b9c19dddc946791a9 [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
Abhishek Patel9017faf2021-09-14 22:48:55 -0500143inline std::optional<bool> getProviderNotifyAction(const std::string& notify)
144{
145 std::optional<bool> notifyAction;
146 if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify")
147 {
148 notifyAction = true;
149 }
150 else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit")
151 {
152 notifyAction = false;
153 }
154
155 return notifyAction;
156}
157
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700158inline static int getJournalMetadata(sd_journal* journal,
159 const std::string_view& field,
160 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700161{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500162 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700163 size_t length = 0;
164 int ret = 0;
165 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800166 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
167 const void** dataVoid = reinterpret_cast<const void**>(&data);
168
169 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700170 if (ret < 0)
171 {
172 return ret;
173 }
Ed Tanous39e77502019-03-04 17:35:53 -0800174 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700175 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000176 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700177 return ret;
178}
179
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700180inline static int getJournalMetadata(sd_journal* journal,
181 const std::string_view& field,
182 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700183{
184 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800185 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700186 // Get the metadata from the requested field of the journal entry
187 ret = getJournalMetadata(journal, field, metadata);
188 if (ret < 0)
189 {
190 return ret;
191 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000192 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700193 return ret;
194}
195
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700196inline static bool getEntryTimestamp(sd_journal* journal,
197 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800198{
199 int ret = 0;
200 uint64_t timestamp = 0;
201 ret = sd_journal_get_realtime_usec(journal, &timestamp);
202 if (ret < 0)
203 {
204 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
205 << strerror(-ret);
206 return false;
207 }
Ed Tanous2b829372022-08-03 14:22:34 -0700208 entryTimestamp =
209 redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500210 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800211}
Ed Tanous50b8a432022-02-03 16:29:50 -0800212
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700213inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
214 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700215{
216 int ret = 0;
217 static uint64_t prevTs = 0;
218 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700219 if (firstEntry)
220 {
221 prevTs = 0;
222 }
223
Jason M. Bills16428a12018-11-02 12:42:29 -0700224 // Get the entry timestamp
225 uint64_t curTs = 0;
226 ret = sd_journal_get_realtime_usec(journal, &curTs);
227 if (ret < 0)
228 {
229 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
230 << strerror(-ret);
231 return false;
232 }
233 // If the timestamp isn't unique, increment the index
234 if (curTs == prevTs)
235 {
236 index++;
237 }
238 else
239 {
240 // Otherwise, reset it
241 index = 0;
242 }
243 // Save the timestamp
244 prevTs = curTs;
245
246 entryID = std::to_string(curTs);
247 if (index > 0)
248 {
249 entryID += "_" + std::to_string(index);
250 }
251 return true;
252}
253
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500254static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700255 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700256{
Ed Tanous271584a2019-07-09 16:24:22 -0700257 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700258 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700259 if (firstEntry)
260 {
261 prevTs = 0;
262 }
263
Jason M. Bills95820182019-04-22 16:25:34 -0700264 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700265 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700266 std::tm timeStruct = {};
267 std::istringstream entryStream(logEntry);
268 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
269 {
270 curTs = std::mktime(&timeStruct);
271 }
272 // If the timestamp isn't unique, increment the index
273 if (curTs == prevTs)
274 {
275 index++;
276 }
277 else
278 {
279 // Otherwise, reset it
280 index = 0;
281 }
282 // Save the timestamp
283 prevTs = curTs;
284
285 entryID = std::to_string(curTs);
286 if (index > 0)
287 {
288 entryID += "_" + std::to_string(index);
289 }
290 return true;
291}
292
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700293inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800294 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
295 const std::string& entryID, uint64_t& timestamp,
296 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700297{
298 if (entryID.empty())
299 {
300 return false;
301 }
302 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800303 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700304
Ed Tanous81ce6092020-12-17 16:54:55 +0000305 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800306 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700307 {
308 // Timestamp has an index
309 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800310 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700311 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700312 auto [ptr, ec] = std::from_chars(
313 indexStr.data(), indexStr.data() + indexStr.size(), index);
314 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700315 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800316 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700317 return false;
318 }
319 }
320 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700321 auto [ptr, ec] =
322 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
323 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700324 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800325 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700326 return false;
327 }
328 return true;
329}
330
Jason M. Bills95820182019-04-22 16:25:34 -0700331static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500332 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700333{
334 static const std::filesystem::path redfishLogDir = "/var/log";
335 static const std::string redfishLogFilename = "redfish";
336
337 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700339 std::filesystem::directory_iterator(redfishLogDir))
340 {
341 // If we find a redfish log file, save the path
342 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700343 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700344 {
345 redfishLogFiles.emplace_back(redfishLogDir / filename);
346 }
347 }
348 // As the log files rotate, they are appended with a ".#" that is higher for
349 // the older logs. Since we don't expect more than 10 log files, we
350 // can just sort the list to get them in order from newest to oldest
351 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
352
353 return !redfishLogFiles.empty();
354}
355
Claire Weinanaefe3782022-07-15 19:17:19 -0700356inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800357 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700358 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700359 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
360{
361 for (const auto& interfaceMap : object.second)
362 {
363 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
364 {
365 for (const auto& propertyMap : interfaceMap.second)
366 {
367 if (propertyMap.first == "Status")
368 {
369 const auto* status =
370 std::get_if<std::string>(&propertyMap.second);
371 if (status == nullptr)
372 {
373 messages::internalError(asyncResp->res);
374 break;
375 }
376 dumpStatus = *status;
377 }
378 }
379 }
380 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
381 {
382 for (const auto& propertyMap : interfaceMap.second)
383 {
384 if (propertyMap.first == "Size")
385 {
386 const auto* sizePtr =
387 std::get_if<uint64_t>(&propertyMap.second);
388 if (sizePtr == nullptr)
389 {
390 messages::internalError(asyncResp->res);
391 break;
392 }
393 size = *sizePtr;
394 break;
395 }
396 }
397 }
398 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
399 {
400 for (const auto& propertyMap : interfaceMap.second)
401 {
402 if (propertyMap.first == "Elapsed")
403 {
404 const uint64_t* usecsTimeStamp =
405 std::get_if<uint64_t>(&propertyMap.second);
406 if (usecsTimeStamp == nullptr)
407 {
408 messages::internalError(asyncResp->res);
409 break;
410 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700411 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700412 break;
413 }
414 }
415 }
416 }
417}
418
Nan Zhou21ab4042022-06-26 23:07:40 +0000419static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800420{
421 std::string entriesPath;
422
423 if (dumpType == "BMC")
424 {
425 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
426 }
427 else if (dumpType == "FaultLog")
428 {
429 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
430 }
431 else if (dumpType == "System")
432 {
433 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
434 }
435 else
436 {
437 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
438 << dumpType;
439 }
440
441 // Returns empty string on error
442 return entriesPath;
443}
444
zhanghch058d1b46d2021-04-01 11:18:24 +0800445inline void
446 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
447 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500448{
Claire Weinanfdd26902022-03-01 14:18:25 -0800449 std::string entriesPath = getDumpEntriesPath(dumpType);
450 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500451 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500452 messages::internalError(asyncResp->res);
453 return;
454 }
455
456 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800457 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800458 dumpType](const boost::system::error_code ec,
459 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 if (ec)
461 {
462 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
463 messages::internalError(asyncResp->res);
464 return;
465 }
466
Claire Weinanfdd26902022-03-01 14:18:25 -0800467 // Remove ending slash
468 std::string odataIdStr = entriesPath;
469 if (!odataIdStr.empty())
470 {
471 odataIdStr.pop_back();
472 }
473
474 asyncResp->res.jsonValue["@odata.type"] =
475 "#LogEntryCollection.LogEntryCollection";
476 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
477 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
478 asyncResp->res.jsonValue["Description"] =
479 "Collection of " + dumpType + " Dump Entries";
480
Ed Tanous002d39b2022-05-31 08:59:27 -0700481 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
482 entriesArray = nlohmann::json::array();
483 std::string dumpEntryPath =
484 "/xyz/openbmc_project/dump/" +
485 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
486
487 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
488 return AlphanumLess<std::string>()(l.first.filename(),
489 r.first.filename());
490 });
491
492 for (auto& object : resp)
493 {
494 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500495 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700496 continue;
497 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700498 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 uint64_t size = 0;
500 std::string dumpStatus;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700501 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700502
503 std::string entryID = object.first.filename();
504 if (entryID.empty())
505 {
506 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500507 }
508
Claire Weinanc6fecda2022-07-15 10:43:25 -0700509 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700510 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700511
512 if (dumpStatus !=
513 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
514 !dumpStatus.empty())
515 {
516 // Dump status is not Complete, no need to enumerate
517 continue;
518 }
519
Vijay Lobo9c11a172021-10-07 16:53:16 -0500520 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800521 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 thisEntry["Id"] = entryID;
523 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700524 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700525 thisEntry["Created"] =
526 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700527
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 if (dumpType == "BMC")
529 {
530 thisEntry["DiagnosticDataType"] = "Manager";
531 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800532 entriesPath + entryID + "/attachment";
533 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700534 }
535 else if (dumpType == "System")
536 {
537 thisEntry["DiagnosticDataType"] = "OEM";
538 thisEntry["OEMDiagnosticDataType"] = "System";
539 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800540 entriesPath + entryID + "/attachment";
541 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 }
543 entriesArray.push_back(std::move(thisEntry));
544 }
545 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500546 },
547 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
548 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
549}
550
zhanghch058d1b46d2021-04-01 11:18:24 +0800551inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700552 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800553 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500554{
Claire Weinanfdd26902022-03-01 14:18:25 -0800555 std::string entriesPath = getDumpEntriesPath(dumpType);
556 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500557 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500558 messages::internalError(asyncResp->res);
559 return;
560 }
561
562 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800563 [asyncResp, entryID, dumpType,
564 entriesPath](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700565 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700566 if (ec)
567 {
568 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
569 messages::internalError(asyncResp->res);
570 return;
571 }
572
573 bool foundDumpEntry = false;
574 std::string dumpEntryPath =
575 "/xyz/openbmc_project/dump/" +
576 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
577
578 for (const auto& objectPath : resp)
579 {
580 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500581 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700582 continue;
583 }
584
585 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700586 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700587 uint64_t size = 0;
588 std::string dumpStatus;
589
Claire Weinanaefe3782022-07-15 19:17:19 -0700590 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700591 timestampUs, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700592
593 if (dumpStatus !=
594 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
595 !dumpStatus.empty())
596 {
597 // Dump status is not Complete
598 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200599 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
600 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500601 return;
602 }
603
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -0500605 "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800606 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700607 asyncResp->res.jsonValue["Id"] = entryID;
608 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700609 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700610 asyncResp->res.jsonValue["Created"] =
611 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500612
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500614 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700615 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
616 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800617 entriesPath + entryID + "/attachment";
618 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500619 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700620 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500621 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700622 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
623 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
624 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800625 entriesPath + entryID + "/attachment";
626 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500627 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700628 }
629 if (!foundDumpEntry)
630 {
631 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
632 messages::internalError(asyncResp->res);
633 return;
634 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500635 },
636 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
637 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
638}
639
zhanghch058d1b46d2021-04-01 11:18:24 +0800640inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800641 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500642 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500643{
Ed Tanous002d39b2022-05-31 08:59:27 -0700644 auto respHandler =
645 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500646 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
647 if (ec)
648 {
George Liu3de8d8b2021-03-22 17:49:39 +0800649 if (ec.value() == EBADR)
650 {
651 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
652 return;
653 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500654 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800655 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 messages::internalError(asyncResp->res);
657 return;
658 }
659 };
660 crow::connections::systemBus->async_method_call(
661 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500662 "/xyz/openbmc_project/dump/" +
663 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
664 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500665 "xyz.openbmc_project.Object.Delete", "Delete");
666}
667
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600668inline DumpCreationProgress
669 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500670{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600671 if (status ==
672 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
673 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
674 {
675 return DumpCreationProgress::DUMP_CREATE_FAILED;
676 }
677 if (status ==
678 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
679 {
680 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
681 }
682 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
683}
684
685inline DumpCreationProgress
686 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
687{
688 for (const auto& [key, val] : values)
689 {
690 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700691 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600692 const std::string* value = std::get_if<std::string>(&val);
693 if (value == nullptr)
694 {
695 BMCWEB_LOG_ERROR << "Status property value is null";
696 return DumpCreationProgress::DUMP_CREATE_FAILED;
697 }
698 return mapDbusStatusToDumpProgress(*value);
699 }
700 }
701 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
702}
703
704inline std::string getDumpEntryPath(const std::string& dumpPath)
705{
706 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
707 {
708 return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
709 }
710 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
711 {
712 return "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
713 }
714 return "";
715}
716
717inline void createDumpTaskCallback(
718 task::Payload&& payload,
719 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
720 const sdbusplus::message::object_path& createdObjPath)
721{
722 const std::string dumpPath = createdObjPath.parent_path().str;
723 const std::string dumpId = createdObjPath.filename();
724
725 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
726
727 if (dumpEntryPath.empty())
728 {
729 BMCWEB_LOG_ERROR << "Invalid dump type received";
730 messages::internalError(asyncResp->res);
731 return;
732 }
733
734 crow::connections::systemBus->async_method_call(
735 [asyncResp, payload, createdObjPath,
736 dumpEntryPath{std::move(dumpEntryPath)},
737 dumpId](const boost::system::error_code ec,
738 const std::string& introspectXml) {
739 if (ec)
740 {
741 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
742 << ec.message();
743 messages::internalError(asyncResp->res);
744 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700745 }
746
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600747 // Check if the created dump object has implemented Progress
748 // interface to track dump completion. If yes, fetch the "Status"
749 // property of the interface, modify the task state accordingly.
750 // Else, return task completed.
751 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700752
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600753 doc.Parse(introspectXml.data(), introspectXml.size());
754 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
755 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700756 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600757 BMCWEB_LOG_ERROR << "XML document failed to parse";
758 messages::internalError(asyncResp->res);
759 return;
760 }
761 tinyxml2::XMLElement* interfaceNode =
762 pRoot->FirstChildElement("interface");
763
764 bool isProgressIntfPresent = false;
765 while (interfaceNode != nullptr)
766 {
767 const char* thisInterfaceName = interfaceNode->Attribute("name");
768 if (thisInterfaceName != nullptr)
769 {
770 if (thisInterfaceName ==
771 std::string_view("xyz.openbmc_project.Common.Progress"))
772 {
773 interfaceNode =
774 interfaceNode->NextSiblingElement("interface");
775 continue;
776 }
777 isProgressIntfPresent = true;
778 break;
779 }
780 interfaceNode = interfaceNode->NextSiblingElement("interface");
781 }
782
783 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
784 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
Patrick Williams5b378542022-11-26 09:41:59 -0600785 boost::system::error_code err, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600786 const std::shared_ptr<task::TaskData>& taskData) {
787 if (err)
788 {
789 BMCWEB_LOG_ERROR << createdObjPath.str
790 << ": Error in creating dump";
791 taskData->messages.emplace_back(messages::internalError());
792 taskData->state = "Cancelled";
793 return task::completed;
794 }
795
796 if (isProgressIntfPresent)
797 {
798 dbus::utility::DBusPropertiesMap values;
799 std::string prop;
800 msg.read(prop, values);
801
802 DumpCreationProgress dumpStatus =
803 getDumpCompletionStatus(values);
804 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
805 {
806 BMCWEB_LOG_ERROR << createdObjPath.str
807 << ": Error in creating dump";
808 taskData->state = "Cancelled";
809 return task::completed;
810 }
811
812 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
813 {
814 BMCWEB_LOG_DEBUG << createdObjPath.str
815 << ": Dump creation task is in progress";
816 return !task::completed;
817 }
818 }
819
Ed Tanous002d39b2022-05-31 08:59:27 -0700820 nlohmann::json retMessage = messages::success();
821 taskData->messages.emplace_back(retMessage);
822
823 std::string headerLoc =
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600824 "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700825 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
826
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600827 BMCWEB_LOG_DEBUG << createdObjPath.str
828 << ": Dump creation task completed";
Ed Tanous002d39b2022-05-31 08:59:27 -0700829 taskData->state = "Completed";
830 return task::completed;
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600831 },
832 "type='signal',interface='org.freedesktop.DBus.Properties',"
833 "member='PropertiesChanged',path='" +
834 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500835
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600836 // The task timer is set to max time limit within which the
837 // requested dump will be collected.
838 task->startTimer(std::chrono::minutes(6));
839 task->populateResp(asyncResp->res);
840 task->payload.emplace(payload);
841 },
842 "xyz.openbmc_project.Dump.Manager", createdObjPath,
843 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500844}
845
zhanghch058d1b46d2021-04-01 11:18:24 +0800846inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
847 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500848{
Claire Weinanfdd26902022-03-01 14:18:25 -0800849 std::string dumpPath = getDumpEntriesPath(dumpType);
850 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500851 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500852 messages::internalError(asyncResp->res);
853 return;
854 }
855
856 std::optional<std::string> diagnosticDataType;
857 std::optional<std::string> oemDiagnosticDataType;
858
Willy Tu15ed6782021-12-14 11:03:16 -0800859 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500860 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
861 "OEMDiagnosticDataType", oemDiagnosticDataType))
862 {
863 return;
864 }
865
866 if (dumpType == "System")
867 {
868 if (!oemDiagnosticDataType || !diagnosticDataType)
869 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800870 BMCWEB_LOG_ERROR
871 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500872 messages::actionParameterMissing(
873 asyncResp->res, "CollectDiagnosticData",
874 "DiagnosticDataType & OEMDiagnosticDataType");
875 return;
876 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700877 if ((*oemDiagnosticDataType != "System") ||
878 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500879 {
880 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700881 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500882 return;
883 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500884 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500885 }
886 else if (dumpType == "BMC")
887 {
888 if (!diagnosticDataType)
889 {
George Liu0fda0f12021-11-16 10:06:17 +0800890 BMCWEB_LOG_ERROR
891 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500892 messages::actionParameterMissing(
893 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
894 return;
895 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700896 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500897 {
898 BMCWEB_LOG_ERROR
899 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700900 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500901 return;
902 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500903 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
904 }
905 else
906 {
907 BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type";
908 messages::internalError(asyncResp->res);
909 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500910 }
911
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600912 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
913 createDumpParamVec;
914
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500915 crow::connections::systemBus->async_method_call(
Patrick Williams5b378542022-11-26 09:41:59 -0600916 [asyncResp, payload(task::Payload(req)), dumpPath](
917 const boost::system::error_code ec, const sdbusplus::message_t& msg,
918 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700919 if (ec)
920 {
921 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500922 const sd_bus_error* dbusError = msg.get_error();
923 if (dbusError == nullptr)
924 {
925 messages::internalError(asyncResp->res);
926 return;
927 }
928
929 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
930 << " and error msg: " << dbusError->message;
931 if (std::string_view(
932 "xyz.openbmc_project.Common.Error.NotAllowed") ==
933 dbusError->name)
934 {
935 messages::resourceInStandby(asyncResp->res);
936 return;
937 }
938 if (std::string_view(
939 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
940 dbusError->name)
941 {
942 messages::serviceDisabled(asyncResp->res, dumpPath);
943 return;
944 }
945 if (std::string_view(
946 "xyz.openbmc_project.Common.Error.Unavailable") ==
947 dbusError->name)
948 {
949 messages::resourceInUse(asyncResp->res);
950 return;
951 }
952 // Other Dbus errors such as:
953 // xyz.openbmc_project.Common.Error.InvalidArgument &
954 // org.freedesktop.DBus.Error.InvalidArgs are all related to
955 // the dbus call that is made here in the bmcweb
956 // implementation and has nothing to do with the client's
957 // input in the request. Hence, returning internal error
958 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700959 messages::internalError(asyncResp->res);
960 return;
961 }
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600962 BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str;
963 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500964 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500965 "xyz.openbmc_project.Dump.Manager",
966 "/xyz/openbmc_project/dump/" +
967 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600968 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500969}
970
zhanghch058d1b46d2021-04-01 11:18:24 +0800971inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
972 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500973{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500974 std::string dumpTypeLowerCopy =
975 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800976
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500977 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800978 [asyncResp, dumpType](
979 const boost::system::error_code ec,
980 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700981 if (ec)
982 {
983 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
984 messages::internalError(asyncResp->res);
985 return;
986 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500987
Ed Tanous002d39b2022-05-31 08:59:27 -0700988 for (const std::string& path : subTreePaths)
989 {
990 sdbusplus::message::object_path objPath(path);
991 std::string logID = objPath.filename();
992 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500993 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700994 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500995 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700996 deleteDumpEntry(asyncResp, logID, dumpType);
997 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500998 },
999 "xyz.openbmc_project.ObjectMapper",
1000 "/xyz/openbmc_project/object_mapper",
1001 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -05001002 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
1003 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
1004 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001005}
1006
Ed Tanousb9d36b42022-02-26 21:42:46 -08001007inline static void
1008 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
1009 std::string& filename, std::string& timestamp,
1010 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001011{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001012 const std::string* filenamePtr = nullptr;
1013 const std::string* timestampPtr = nullptr;
1014 const std::string* logfilePtr = nullptr;
1015
1016 const bool success = sdbusplus::unpackPropertiesNoThrow(
1017 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1018 "Filename", filenamePtr, "Log", logfilePtr);
1019
1020 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001021 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001022 return;
1023 }
1024
1025 if (filenamePtr != nullptr)
1026 {
1027 filename = *filenamePtr;
1028 }
1029
1030 if (timestampPtr != nullptr)
1031 {
1032 timestamp = *timestampPtr;
1033 }
1034
1035 if (logfilePtr != nullptr)
1036 {
1037 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001038 }
1039}
1040
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001041constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001042inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001043{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001044 /**
1045 * Functions triggers appropriate requests on DBus
1046 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001047 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001048 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001049 .methods(boost::beast::http::verb::get)(
1050 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001051 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1052 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001053 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001054 {
1055 return;
1056 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001057 if (systemName != "system")
1058 {
1059 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1060 systemName);
1061 return;
1062 }
1063
Ed Tanous002d39b2022-05-31 08:59:27 -07001064 // Collections don't include the static data added by SubRoute
1065 // because it has a duplicate entry for members
1066 asyncResp->res.jsonValue["@odata.type"] =
1067 "#LogServiceCollection.LogServiceCollection";
1068 asyncResp->res.jsonValue["@odata.id"] =
1069 "/redfish/v1/Systems/system/LogServices";
1070 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1071 asyncResp->res.jsonValue["Description"] =
1072 "Collection of LogServices for this Computer System";
1073 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1074 logServiceArray = nlohmann::json::array();
1075 nlohmann::json::object_t eventLog;
1076 eventLog["@odata.id"] =
1077 "/redfish/v1/Systems/system/LogServices/EventLog";
1078 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001079#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001080 nlohmann::json::object_t dumpLog;
1081 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
1082 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -06001083#endif
1084
Jason M. Billsd53dd412019-02-12 17:16:22 -08001085#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001086 nlohmann::json::object_t crashdump;
1087 crashdump["@odata.id"] =
1088 "/redfish/v1/Systems/system/LogServices/Crashdump";
1089 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -08001090#endif
Spencer Kub7028eb2021-10-26 15:27:35 +08001091
1092#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -07001093 nlohmann::json::object_t hostlogger;
1094 hostlogger["@odata.id"] =
1095 "/redfish/v1/Systems/system/LogServices/HostLogger";
1096 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +08001097#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07001098 asyncResp->res.jsonValue["Members@odata.count"] =
1099 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001100
Ed Tanous002d39b2022-05-31 08:59:27 -07001101 crow::connections::systemBus->async_method_call(
1102 [asyncResp](const boost::system::error_code ec,
1103 const dbus::utility::MapperGetSubTreePathsResponse&
1104 subtreePath) {
1105 if (ec)
1106 {
1107 BMCWEB_LOG_ERROR << ec;
1108 return;
1109 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001110
Ed Tanous002d39b2022-05-31 08:59:27 -07001111 for (const auto& pathStr : subtreePath)
1112 {
1113 if (pathStr.find("PostCode") != std::string::npos)
1114 {
1115 nlohmann::json& logServiceArrayLocal =
1116 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -07001117 nlohmann::json::object_t member;
1118 member["@odata.id"] =
1119 "/redfish/v1/Systems/system/LogServices/PostCodes";
1120
1121 logServiceArrayLocal.push_back(std::move(member));
1122
Ed Tanous002d39b2022-05-31 08:59:27 -07001123 asyncResp->res.jsonValue["Members@odata.count"] =
1124 logServiceArrayLocal.size();
1125 return;
1126 }
1127 }
1128 },
1129 "xyz.openbmc_project.ObjectMapper",
1130 "/xyz/openbmc_project/object_mapper",
1131 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
1132 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -07001133 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001134}
1135
1136inline void requestRoutesEventLogService(App& app)
1137{
Ed Tanous22d268c2022-05-19 09:39:07 -07001138 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001139 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001140 .methods(boost::beast::http::verb::get)(
1141 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001142 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1143 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001144 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001145 {
1146 return;
1147 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001148 if (systemName != "system")
1149 {
1150 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1151 systemName);
1152 return;
1153 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001154 asyncResp->res.jsonValue["@odata.id"] =
1155 "/redfish/v1/Systems/system/LogServices/EventLog";
1156 asyncResp->res.jsonValue["@odata.type"] =
1157 "#LogService.v1_1_0.LogService";
1158 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1159 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1160 asyncResp->res.jsonValue["Id"] = "EventLog";
1161 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301162
Ed Tanous002d39b2022-05-31 08:59:27 -07001163 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001164 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301165
Ed Tanous002d39b2022-05-31 08:59:27 -07001166 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1167 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1168 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301169
Ed Tanous002d39b2022-05-31 08:59:27 -07001170 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1171 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1172 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001173
Ed Tanous002d39b2022-05-31 08:59:27 -07001174 {"target",
1175 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001176 });
1177}
1178
1179inline void requestRoutesJournalEventLogClear(App& app)
1180{
Jason M. Bills4978b632022-02-22 14:17:43 -08001181 BMCWEB_ROUTE(
1182 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001183 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001184 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001185 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001186 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1188 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001189 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001190 {
1191 return;
1192 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001193 if (systemName != "system")
1194 {
1195 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1196 systemName);
1197 return;
1198 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001199 // Clear the EventLog by deleting the log files
1200 std::vector<std::filesystem::path> redfishLogFiles;
1201 if (getRedfishLogFiles(redfishLogFiles))
1202 {
1203 for (const std::filesystem::path& file : redfishLogFiles)
1204 {
1205 std::error_code ec;
1206 std::filesystem::remove(file, ec);
1207 }
1208 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001209
Ed Tanous002d39b2022-05-31 08:59:27 -07001210 // Reload rsyslog so it knows to start new log files
1211 crow::connections::systemBus->async_method_call(
1212 [asyncResp](const boost::system::error_code ec) {
1213 if (ec)
1214 {
1215 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1216 messages::internalError(asyncResp->res);
1217 return;
1218 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001219
Ed Tanous002d39b2022-05-31 08:59:27 -07001220 messages::success(asyncResp->res);
1221 },
1222 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1223 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1224 "replace");
1225 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001226}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001227
Jason M. Billsac992cd2022-06-24 13:31:46 -07001228enum class LogParseError
1229{
1230 success,
1231 parseFailed,
1232 messageIdNotInRegistry,
1233};
1234
1235static LogParseError
1236 fillEventLogEntryJson(const std::string& logEntryID,
1237 const std::string& logEntry,
1238 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001239{
Jason M. Bills95820182019-04-22 16:25:34 -07001240 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001241 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001242 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001243 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001244 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001245 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001246 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001247 std::string timestamp = logEntry.substr(0, space);
1248 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001249 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001250 if (entryStart == std::string::npos)
1251 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001252 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001253 }
1254 std::string_view entry(logEntry);
1255 entry.remove_prefix(entryStart);
1256 // Use split to separate the entry into its fields
1257 std::vector<std::string> logEntryFields;
1258 boost::split(logEntryFields, entry, boost::is_any_of(","),
1259 boost::token_compress_on);
1260 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001261 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001262 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001263 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001264 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001265 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001266
Jason M. Bills4851d452019-03-28 11:27:48 -07001267 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001268 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001269
Sui Chen54417b02022-03-24 14:59:52 -07001270 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001271 {
Sui Chen54417b02022-03-24 14:59:52 -07001272 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001273 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001274 }
1275
Sui Chen54417b02022-03-24 14:59:52 -07001276 std::string msg = message->message;
1277
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001278 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001279 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001280 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001281 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001282 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001283 // If the first string is empty, assume there are no MessageArgs
1284 std::size_t messageArgsSize = 0;
1285 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001286 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001287 messageArgsSize = logEntryFields.size() - 1;
1288 }
1289
Ed Tanous23a21a12020-07-25 04:45:05 +00001290 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001291
1292 // Fill the MessageArgs into the Message
1293 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001294 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001295 {
1296 std::string argStr = "%" + std::to_string(++i);
1297 size_t argPos = msg.find(argStr);
1298 if (argPos != std::string::npos)
1299 {
1300 msg.replace(argPos, argStr.length(), messageArg);
1301 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001302 }
1303 }
1304
Jason M. Bills95820182019-04-22 16:25:34 -07001305 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1306 // format which matches the Redfish format except for the fractional seconds
1307 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001308 std::size_t dot = timestamp.find_first_of('.');
1309 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001310 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001311 {
Jason M. Bills95820182019-04-22 16:25:34 -07001312 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001313 }
1314
1315 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001316 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001317 logEntryJson["@odata.id"] =
1318 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1319 logEntryJson["Name"] = "System Event Log Entry";
1320 logEntryJson["Id"] = logEntryID;
1321 logEntryJson["Message"] = std::move(msg);
1322 logEntryJson["MessageId"] = std::move(messageID);
1323 logEntryJson["MessageArgs"] = messageArgs;
1324 logEntryJson["EntryType"] = "Event";
1325 logEntryJson["Severity"] = message->messageSeverity;
1326 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001327 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001328}
1329
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001330inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001331{
Ed Tanous22d268c2022-05-19 09:39:07 -07001332 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001333 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001334 .methods(boost::beast::http::verb::get)(
1335 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001336 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1337 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001338 query_param::QueryCapabilities capabilities = {
1339 .canDelegateTop = true,
1340 .canDelegateSkip = true,
1341 };
1342 query_param::Query delegatedQuery;
1343 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001344 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001345 {
1346 return;
1347 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001348 if (systemName != "system")
1349 {
1350 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1351 systemName);
1352 return;
1353 }
1354
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001355 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001356 size_t skip = delegatedQuery.skip.value_or(0);
1357
Ed Tanous002d39b2022-05-31 08:59:27 -07001358 // Collections don't include the static data added by SubRoute
1359 // because it has a duplicate entry for members
1360 asyncResp->res.jsonValue["@odata.type"] =
1361 "#LogEntryCollection.LogEntryCollection";
1362 asyncResp->res.jsonValue["@odata.id"] =
1363 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1364 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1365 asyncResp->res.jsonValue["Description"] =
1366 "Collection of System Event Log Entries";
1367
1368 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1369 logEntryArray = nlohmann::json::array();
1370 // Go through the log files and create a unique ID for each
1371 // entry
1372 std::vector<std::filesystem::path> redfishLogFiles;
1373 getRedfishLogFiles(redfishLogFiles);
1374 uint64_t entryCount = 0;
1375 std::string logEntry;
1376
1377 // Oldest logs are in the last file, so start there and loop
1378 // backwards
1379 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1380 it++)
1381 {
1382 std::ifstream logStream(*it);
1383 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001384 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001385 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001386 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001387
Ed Tanous002d39b2022-05-31 08:59:27 -07001388 // Reset the unique ID on the first entry
1389 bool firstEntry = true;
1390 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001391 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 std::string idStr;
1393 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001394 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001395 continue;
1396 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001397 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001398
Jason M. Billsde703c52022-06-23 14:19:04 -07001399 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001400 LogParseError status =
1401 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1402 if (status == LogParseError::messageIdNotInRegistry)
1403 {
1404 continue;
1405 }
1406 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 {
1408 messages::internalError(asyncResp->res);
1409 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001410 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001411
Jason M. Billsde703c52022-06-23 14:19:04 -07001412 entryCount++;
1413 // Handle paging using skip (number of entries to skip from the
1414 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001415 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001416 {
1417 continue;
1418 }
1419
1420 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001421 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001422 }
1423 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001424 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001425 {
1426 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1427 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001428 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001429 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001430 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001431}
Chicago Duan336e96c2019-07-15 14:22:08 +08001432
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001433inline void requestRoutesJournalEventLogEntry(App& app)
1434{
1435 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001436 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001437 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001438 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001439 [&app](const crow::Request& req,
1440 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001441 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001442 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001443 {
1444 return;
1445 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001446
1447 if (systemName != "system")
1448 {
1449 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1450 systemName);
1451 return;
1452 }
1453
Ed Tanous002d39b2022-05-31 08:59:27 -07001454 const std::string& targetID = param;
1455
1456 // Go through the log files and check the unique ID for each
1457 // entry to find the target entry
1458 std::vector<std::filesystem::path> redfishLogFiles;
1459 getRedfishLogFiles(redfishLogFiles);
1460 std::string logEntry;
1461
1462 // Oldest logs are in the last file, so start there and loop
1463 // backwards
1464 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1465 it++)
1466 {
1467 std::ifstream logStream(*it);
1468 if (!logStream.is_open())
1469 {
1470 continue;
1471 }
1472
1473 // Reset the unique ID on the first entry
1474 bool firstEntry = true;
1475 while (std::getline(logStream, logEntry))
1476 {
1477 std::string idStr;
1478 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001479 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001480 continue;
1481 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001482 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001483
1484 if (idStr == targetID)
1485 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001486 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001487 LogParseError status =
1488 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1489 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001490 {
1491 messages::internalError(asyncResp->res);
1492 return;
1493 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001494 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001495 return;
1496 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001497 }
1498 }
1499 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001500 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07001501 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001502}
1503
1504inline void requestRoutesDBusEventLogEntryCollection(App& app)
1505{
Ed Tanous22d268c2022-05-19 09:39:07 -07001506 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001507 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001508 .methods(boost::beast::http::verb::get)(
1509 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001510 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1511 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001512 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001513 {
1514 return;
1515 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001516 if (systemName != "system")
1517 {
1518 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1519 systemName);
1520 return;
1521 }
1522
Ed Tanous002d39b2022-05-31 08:59:27 -07001523 // Collections don't include the static data added by SubRoute
1524 // because it has a duplicate entry for members
1525 asyncResp->res.jsonValue["@odata.type"] =
1526 "#LogEntryCollection.LogEntryCollection";
1527 asyncResp->res.jsonValue["@odata.id"] =
1528 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1529 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1530 asyncResp->res.jsonValue["Description"] =
1531 "Collection of System Event Log Entries";
1532
1533 // DBus implementation of EventLog/Entries
1534 // Make call to Logging Service to find all log entry objects
1535 crow::connections::systemBus->async_method_call(
1536 [asyncResp](const boost::system::error_code ec,
1537 const dbus::utility::ManagedObjectType& resp) {
1538 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001539 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001540 // TODO Handle for specific error code
1541 BMCWEB_LOG_ERROR
1542 << "getLogEntriesIfaceData resp_handler got error " << ec;
1543 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001544 return;
1545 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001546 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1547 entriesArray = nlohmann::json::array();
1548 for (const auto& objectPath : resp)
1549 {
1550 const uint32_t* id = nullptr;
1551 const uint64_t* timestamp = nullptr;
1552 const uint64_t* updateTimestamp = nullptr;
1553 const std::string* severity = nullptr;
1554 const std::string* message = nullptr;
1555 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001556 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001557 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001558 const std::string* notify = nullptr;
1559
Ed Tanous002d39b2022-05-31 08:59:27 -07001560 for (const auto& interfaceMap : objectPath.second)
1561 {
1562 if (interfaceMap.first ==
1563 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001564 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001565 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001566 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001567 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001568 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001569 id = std::get_if<uint32_t>(&propertyMap.second);
1570 }
1571 else if (propertyMap.first == "Timestamp")
1572 {
1573 timestamp =
1574 std::get_if<uint64_t>(&propertyMap.second);
1575 }
1576 else if (propertyMap.first == "UpdateTimestamp")
1577 {
1578 updateTimestamp =
1579 std::get_if<uint64_t>(&propertyMap.second);
1580 }
1581 else if (propertyMap.first == "Severity")
1582 {
1583 severity = std::get_if<std::string>(
1584 &propertyMap.second);
1585 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001586 else if (propertyMap.first == "Resolution")
1587 {
1588 resolution = std::get_if<std::string>(
1589 &propertyMap.second);
1590 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001591 else if (propertyMap.first == "Message")
1592 {
1593 message = std::get_if<std::string>(
1594 &propertyMap.second);
1595 }
1596 else if (propertyMap.first == "Resolved")
1597 {
1598 const bool* resolveptr =
1599 std::get_if<bool>(&propertyMap.second);
1600 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001601 {
1602 messages::internalError(asyncResp->res);
1603 return;
1604 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001605 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001606 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001607 else if (propertyMap.first ==
1608 "ServiceProviderNotify")
1609 {
1610 notify = std::get_if<std::string>(
1611 &propertyMap.second);
1612 if (notify == nullptr)
1613 {
1614 messages::internalError(asyncResp->res);
1615 return;
1616 }
1617 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001618 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001619 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001620 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001621 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 messages::internalError(asyncResp->res);
1623 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001624 }
1625 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001626 else if (interfaceMap.first ==
1627 "xyz.openbmc_project.Common.FilePath")
1628 {
1629 for (const auto& propertyMap : interfaceMap.second)
1630 {
1631 if (propertyMap.first == "Path")
1632 {
1633 filePath = std::get_if<std::string>(
1634 &propertyMap.second);
1635 }
1636 }
1637 }
1638 }
1639 // Object path without the
1640 // xyz.openbmc_project.Logging.Entry interface, ignore
1641 // and continue.
1642 if (id == nullptr || message == nullptr ||
1643 severity == nullptr || timestamp == nullptr ||
1644 updateTimestamp == nullptr)
1645 {
1646 continue;
1647 }
1648 entriesArray.push_back({});
1649 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001650 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001651 thisEntry["@odata.id"] =
1652 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1653 std::to_string(*id);
1654 thisEntry["Name"] = "System Event Log Entry";
1655 thisEntry["Id"] = std::to_string(*id);
1656 thisEntry["Message"] = *message;
1657 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001658 if ((resolution != nullptr) && (!(*resolution).empty()))
1659 {
1660 thisEntry["Resolution"] = *resolution;
1661 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001662 std::optional<bool> notifyAction =
1663 getProviderNotifyAction(*notify);
1664 if (notifyAction)
1665 {
1666 thisEntry["ServiceProviderNotified"] = *notifyAction;
1667 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001668 thisEntry["EntryType"] = "Event";
1669 thisEntry["Severity"] =
1670 translateSeverityDbusToRedfish(*severity);
1671 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001672 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001673 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001674 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001675 if (filePath != nullptr)
1676 {
1677 thisEntry["AdditionalDataURI"] =
1678 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1679 std::to_string(*id) + "/attachment";
1680 }
1681 }
1682 std::sort(
1683 entriesArray.begin(), entriesArray.end(),
1684 [](const nlohmann::json& left, const nlohmann::json& right) {
1685 return (left["Id"] <= right["Id"]);
1686 });
1687 asyncResp->res.jsonValue["Members@odata.count"] =
1688 entriesArray.size();
1689 },
1690 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1691 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001692 });
1693}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001694
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001695inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001696{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001697 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001698 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001699 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001700 .methods(boost::beast::http::verb::get)(
1701 [&app](const crow::Request& req,
1702 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001703 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001704 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001705 {
1706 return;
1707 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001708 if (systemName != "system")
1709 {
1710 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1711 systemName);
1712 return;
1713 }
1714
Ed Tanous002d39b2022-05-31 08:59:27 -07001715 std::string entryID = param;
1716 dbus::utility::escapePathForDbus(entryID);
1717
1718 // DBus implementation of EventLog/Entries
1719 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001720 sdbusplus::asio::getAllProperties(
1721 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1722 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001723 [asyncResp, entryID](const boost::system::error_code ec,
1724 const dbus::utility::DBusPropertiesMap& resp) {
1725 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001726 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001727 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1728 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001729 return;
1730 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001731 if (ec)
1732 {
1733 BMCWEB_LOG_ERROR
1734 << "EventLogEntry (DBus) resp_handler got error " << ec;
1735 messages::internalError(asyncResp->res);
1736 return;
1737 }
1738 const uint32_t* id = nullptr;
1739 const uint64_t* timestamp = nullptr;
1740 const uint64_t* updateTimestamp = nullptr;
1741 const std::string* severity = nullptr;
1742 const std::string* message = nullptr;
1743 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001744 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001745 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001746 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001747
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001748 const bool success = sdbusplus::unpackPropertiesNoThrow(
1749 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1750 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001751 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05001752 "Resolution", resolution, "Path", filePath,
1753 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001754
1755 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001756 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001757 messages::internalError(asyncResp->res);
1758 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001759 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001760
Ed Tanous002d39b2022-05-31 08:59:27 -07001761 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05001762 timestamp == nullptr || updateTimestamp == nullptr ||
1763 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001764 {
1765 messages::internalError(asyncResp->res);
1766 return;
1767 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001768
Ed Tanous002d39b2022-05-31 08:59:27 -07001769 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001770 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001771 asyncResp->res.jsonValue["@odata.id"] =
1772 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1773 std::to_string(*id);
1774 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1775 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1776 asyncResp->res.jsonValue["Message"] = *message;
1777 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001778 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
1779 if (notifyAction)
1780 {
1781 asyncResp->res.jsonValue["ServiceProviderNotified"] =
1782 *notifyAction;
1783 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001784 if ((resolution != nullptr) && (!(*resolution).empty()))
1785 {
1786 asyncResp->res.jsonValue["Resolution"] = *resolution;
1787 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001788 asyncResp->res.jsonValue["EntryType"] = "Event";
1789 asyncResp->res.jsonValue["Severity"] =
1790 translateSeverityDbusToRedfish(*severity);
1791 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001792 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001793 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001794 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 if (filePath != nullptr)
1796 {
1797 asyncResp->res.jsonValue["AdditionalDataURI"] =
1798 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1799 std::to_string(*id) + "/attachment";
1800 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001801 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001802 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001803
1804 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001805 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001806 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001807 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001808 [&app](const crow::Request& req,
1809 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001810 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001811 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001812 {
1813 return;
1814 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001815 if (systemName != "system")
1816 {
1817 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1818 systemName);
1819 return;
1820 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001821 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001822
Ed Tanous002d39b2022-05-31 08:59:27 -07001823 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1824 resolved))
1825 {
1826 return;
1827 }
1828 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001829
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 crow::connections::systemBus->async_method_call(
1831 [asyncResp, entryId](const boost::system::error_code ec) {
1832 if (ec)
1833 {
1834 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1835 messages::internalError(asyncResp->res);
1836 return;
1837 }
1838 },
1839 "xyz.openbmc_project.Logging",
1840 "/xyz/openbmc_project/logging/entry/" + entryId,
1841 "org.freedesktop.DBus.Properties", "Set",
1842 "xyz.openbmc_project.Logging.Entry", "Resolved",
1843 dbus::utility::DbusVariantType(*resolved));
1844 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001845
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001846 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001847 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001848 .privileges(redfish::privileges::deleteLogEntry)
1849
Ed Tanous002d39b2022-05-31 08:59:27 -07001850 .methods(boost::beast::http::verb::delete_)(
1851 [&app](const crow::Request& req,
1852 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001853 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001854 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001855 {
1856 return;
1857 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001858 if (systemName != "system")
1859 {
1860 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1861 systemName);
1862 return;
1863 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001864 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1865
1866 std::string entryID = param;
1867
1868 dbus::utility::escapePathForDbus(entryID);
1869
1870 // Process response from Logging service.
1871 auto respHandler =
1872 [asyncResp, entryID](const boost::system::error_code ec) {
1873 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1874 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001875 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001876 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001877 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001878 messages::resourceNotFound(asyncResp->res, "LogEntry",
1879 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001880 return;
1881 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001882 // TODO Handle for specific error code
1883 BMCWEB_LOG_ERROR
1884 << "EventLogEntry (DBus) doDelete respHandler got error "
1885 << ec;
1886 asyncResp->res.result(
1887 boost::beast::http::status::internal_server_error);
1888 return;
1889 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001890
Ed Tanous002d39b2022-05-31 08:59:27 -07001891 asyncResp->res.result(boost::beast::http::status::ok);
1892 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001893
Ed Tanous002d39b2022-05-31 08:59:27 -07001894 // Make call to Logging service to request Delete Log
1895 crow::connections::systemBus->async_method_call(
1896 respHandler, "xyz.openbmc_project.Logging",
1897 "/xyz/openbmc_project/logging/entry/" + entryID,
1898 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001899 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001900}
1901
1902inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001903{
George Liu0fda0f12021-11-16 10:06:17 +08001904 BMCWEB_ROUTE(
1905 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001906 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001907 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001908 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001909 [&app](const crow::Request& req,
1910 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001911 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001912 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001913 {
1914 return;
1915 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001916 if (http_helpers::isContentTypeAllowed(
1917 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001918 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001919 {
1920 asyncResp->res.result(boost::beast::http::status::bad_request);
1921 return;
1922 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001923 if (systemName != "system")
1924 {
1925 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1926 systemName);
1927 return;
1928 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001929
Ed Tanous002d39b2022-05-31 08:59:27 -07001930 std::string entryID = param;
1931 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001932
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 crow::connections::systemBus->async_method_call(
1934 [asyncResp, entryID](const boost::system::error_code ec,
1935 const sdbusplus::message::unix_fd& unixfd) {
1936 if (ec.value() == EBADR)
1937 {
1938 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1939 entryID);
1940 return;
1941 }
1942 if (ec)
1943 {
1944 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1945 messages::internalError(asyncResp->res);
1946 return;
1947 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001948
Ed Tanous002d39b2022-05-31 08:59:27 -07001949 int fd = -1;
1950 fd = dup(unixfd);
1951 if (fd == -1)
1952 {
1953 messages::internalError(asyncResp->res);
1954 return;
1955 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001956
Ed Tanous002d39b2022-05-31 08:59:27 -07001957 long long int size = lseek(fd, 0, SEEK_END);
1958 if (size == -1)
1959 {
1960 messages::internalError(asyncResp->res);
1961 return;
1962 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001963
Ed Tanous002d39b2022-05-31 08:59:27 -07001964 // Arbitrary max size of 64kb
1965 constexpr int maxFileSize = 65536;
1966 if (size > maxFileSize)
1967 {
1968 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1969 << maxFileSize;
1970 messages::internalError(asyncResp->res);
1971 return;
1972 }
1973 std::vector<char> data(static_cast<size_t>(size));
1974 long long int rc = lseek(fd, 0, SEEK_SET);
1975 if (rc == -1)
1976 {
1977 messages::internalError(asyncResp->res);
1978 return;
1979 }
1980 rc = read(fd, data.data(), data.size());
1981 if ((rc == -1) || (rc != size))
1982 {
1983 messages::internalError(asyncResp->res);
1984 return;
1985 }
1986 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001987
Ed Tanous002d39b2022-05-31 08:59:27 -07001988 std::string_view strData(data.data(), data.size());
1989 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001990
Ed Tanousd9f6c622022-03-17 09:12:17 -07001991 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001992 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001993 asyncResp->res.addHeader(
1994 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001995 asyncResp->res.body() = std::move(output);
1996 },
1997 "xyz.openbmc_project.Logging",
1998 "/xyz/openbmc_project/logging/entry/" + entryID,
1999 "xyz.openbmc_project.Logging.Entry", "GetEntry");
2000 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002001}
2002
Spencer Kub7028eb2021-10-26 15:27:35 +08002003constexpr const char* hostLoggerFolderPath = "/var/log/console";
2004
2005inline bool
2006 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2007 std::vector<std::filesystem::path>& hostLoggerFiles)
2008{
2009 std::error_code ec;
2010 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2011 if (ec)
2012 {
2013 BMCWEB_LOG_ERROR << ec.message();
2014 return false;
2015 }
2016 for (const std::filesystem::directory_entry& it : logPath)
2017 {
2018 std::string filename = it.path().filename();
2019 // Prefix of each log files is "log". Find the file and save the
2020 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002021 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002022 {
2023 hostLoggerFiles.emplace_back(it.path());
2024 }
2025 }
2026 // As the log files rotate, they are appended with a ".#" that is higher for
2027 // the older logs. Since we start from oldest logs, sort the name in
2028 // descending order.
2029 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2030 AlphanumLess<std::string>());
2031
2032 return true;
2033}
2034
Ed Tanous02cad962022-06-30 16:50:15 -07002035inline bool getHostLoggerEntries(
2036 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2037 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002038{
2039 GzFileReader logFile;
2040
2041 // Go though all log files and expose host logs.
2042 for (const std::filesystem::path& it : hostLoggerFiles)
2043 {
2044 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2045 {
2046 BMCWEB_LOG_ERROR << "fail to expose host logs";
2047 return false;
2048 }
2049 }
2050 // Get lastMessage from constructor by getter
2051 std::string lastMessage = logFile.getLastMessage();
2052 if (!lastMessage.empty())
2053 {
2054 logCount++;
2055 if (logCount > skip && logCount <= (skip + top))
2056 {
2057 logEntries.push_back(lastMessage);
2058 }
2059 }
2060 return true;
2061}
2062
2063inline void fillHostLoggerEntryJson(const std::string& logEntryID,
2064 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002065 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002066{
2067 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002068 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002069 logEntryJson["@odata.id"] =
2070 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
2071 logEntryID;
2072 logEntryJson["Name"] = "Host Logger Entry";
2073 logEntryJson["Id"] = logEntryID;
2074 logEntryJson["Message"] = msg;
2075 logEntryJson["EntryType"] = "Oem";
2076 logEntryJson["Severity"] = "OK";
2077 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002078}
2079
2080inline void requestRoutesSystemHostLogger(App& app)
2081{
Ed Tanous22d268c2022-05-19 09:39:07 -07002082 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002083 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002084 .methods(boost::beast::http::verb::get)(
2085 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002086 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2087 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002088 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002089 {
2090 return;
2091 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002092 if (systemName != "system")
2093 {
2094 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2095 systemName);
2096 return;
2097 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002098 asyncResp->res.jsonValue["@odata.id"] =
2099 "/redfish/v1/Systems/system/LogServices/HostLogger";
2100 asyncResp->res.jsonValue["@odata.type"] =
2101 "#LogService.v1_1_0.LogService";
2102 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2103 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2104 asyncResp->res.jsonValue["Id"] = "HostLogger";
2105 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2106 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2107 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002108}
2109
2110inline void requestRoutesSystemHostLoggerCollection(App& app)
2111{
2112 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002113 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002114 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002115 .methods(boost::beast::http::verb::get)(
2116 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002117 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2118 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002119 query_param::QueryCapabilities capabilities = {
2120 .canDelegateTop = true,
2121 .canDelegateSkip = true,
2122 };
2123 query_param::Query delegatedQuery;
2124 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002125 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002126 {
2127 return;
2128 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002129 if (systemName != "system")
2130 {
2131 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2132 systemName);
2133 return;
2134 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002135 asyncResp->res.jsonValue["@odata.id"] =
2136 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2137 asyncResp->res.jsonValue["@odata.type"] =
2138 "#LogEntryCollection.LogEntryCollection";
2139 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2140 asyncResp->res.jsonValue["Description"] =
2141 "Collection of HostLogger Entries";
2142 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2143 logEntryArray = nlohmann::json::array();
2144 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002145
Ed Tanous002d39b2022-05-31 08:59:27 -07002146 std::vector<std::filesystem::path> hostLoggerFiles;
2147 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2148 {
2149 BMCWEB_LOG_ERROR << "fail to get host log file path";
2150 return;
2151 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002152 // If we weren't provided top and skip limits, use the defaults.
2153 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002154 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002155 size_t logCount = 0;
2156 // This vector only store the entries we want to expose that
2157 // control by skip and top.
2158 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002159 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2160 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002161 {
2162 messages::internalError(asyncResp->res);
2163 return;
2164 }
2165 // If vector is empty, that means skip value larger than total
2166 // log count
2167 if (logEntries.empty())
2168 {
2169 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2170 return;
2171 }
2172 if (!logEntries.empty())
2173 {
2174 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002175 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002176 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002177 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2178 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002179 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002180 }
2181
Ed Tanous002d39b2022-05-31 08:59:27 -07002182 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002183 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002184 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2186 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002187 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002188 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 }
George Liu0fda0f12021-11-16 10:06:17 +08002190 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002191}
2192
2193inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2194{
2195 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002196 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002197 .privileges(redfish::privileges::getLogEntry)
2198 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002199 [&app](const crow::Request& req,
2200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002201 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002202 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002203 {
2204 return;
2205 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002206 if (systemName != "system")
2207 {
2208 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2209 systemName);
2210 return;
2211 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002212 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002213
Ed Tanous002d39b2022-05-31 08:59:27 -07002214 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002215
Ed Tanous002d39b2022-05-31 08:59:27 -07002216 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2217 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002218
Ed Tanous002d39b2022-05-31 08:59:27 -07002219 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002220 if (ec == std::errc::invalid_argument ||
2221 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002222 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002223 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002224 return;
2225 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002226
Ed Tanous002d39b2022-05-31 08:59:27 -07002227 std::vector<std::filesystem::path> hostLoggerFiles;
2228 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2229 {
2230 BMCWEB_LOG_ERROR << "fail to get host log file path";
2231 return;
2232 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002233
Ed Tanous002d39b2022-05-31 08:59:27 -07002234 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002235 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002236 std::vector<std::string> logEntries;
2237 // We can get specific entry by skip and top. For example, if we
2238 // want to get nth entry, we can set skip = n-1 and top = 1 to
2239 // get that entry
2240 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2241 logCount))
2242 {
2243 messages::internalError(asyncResp->res);
2244 return;
2245 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002246
Ed Tanous002d39b2022-05-31 08:59:27 -07002247 if (!logEntries.empty())
2248 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002249 nlohmann::json::object_t hostLogEntry;
2250 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2251 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002252 return;
2253 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002254
Ed Tanous002d39b2022-05-31 08:59:27 -07002255 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002256 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002257 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002258}
2259
Claire Weinanfdd26902022-03-01 14:18:25 -08002260constexpr char const* dumpManagerIface =
2261 "xyz.openbmc_project.Collection.DeleteAll";
Claire Weinandd72e872022-08-15 14:20:06 -07002262inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002263 crow::App& app, const crow::Request& req,
2264 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2265{
2266 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2267 {
2268 return;
2269 }
2270 // Collections don't include the static data added by SubRoute
2271 // because it has a duplicate entry for members
2272 asyncResp->res.jsonValue["@odata.type"] =
2273 "#LogServiceCollection.LogServiceCollection";
2274 asyncResp->res.jsonValue["@odata.id"] =
2275 "/redfish/v1/Managers/bmc/LogServices";
2276 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2277 asyncResp->res.jsonValue["Description"] =
2278 "Collection of LogServices for this Manager";
2279 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2280 logServiceArray = nlohmann::json::array();
2281
2282#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002283 nlohmann::json::object_t journal;
2284 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2285 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002286#endif
2287
2288 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2289
2290#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2291 auto respHandler =
2292 [asyncResp](
2293 const boost::system::error_code ec,
2294 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2295 if (ec)
2296 {
2297 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002298 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002299 << ec;
2300 // Assume that getting an error simply means there are no dump
2301 // LogServices. Return without adding any error response.
2302 return;
2303 }
2304
2305 nlohmann::json& logServiceArrayLocal =
2306 asyncResp->res.jsonValue["Members"];
2307
2308 for (const std::string& path : subTreePaths)
2309 {
2310 if (path == "/xyz/openbmc_project/dump/bmc")
2311 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002312 nlohmann::json::object_t member;
2313 member["@odata.id"] =
2314 "/redfish/v1/Managers/bmc/LogServices/Dump";
2315 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002316 }
2317 else if (path == "/xyz/openbmc_project/dump/faultlog")
2318 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002319 nlohmann::json::object_t member;
2320 member["@odata.id"] =
2321 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2322 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002323 }
2324 }
2325
2326 asyncResp->res.jsonValue["Members@odata.count"] =
2327 logServiceArrayLocal.size();
2328 };
2329
2330 crow::connections::systemBus->async_method_call(
2331 respHandler, "xyz.openbmc_project.ObjectMapper",
2332 "/xyz/openbmc_project/object_mapper",
2333 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2334 "/xyz/openbmc_project/dump", 0,
2335 std::array<const char*, 1>{dumpManagerIface});
2336#endif
2337}
2338
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002339inline void requestRoutesBMCLogServiceCollection(App& app)
2340{
2341 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002342 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002343 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002344 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002345}
Ed Tanous1da66f72018-07-27 16:13:37 -07002346
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002347inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002348{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002349 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002350 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002351 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002352 [&app](const crow::Request& req,
2353 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002354 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002355 {
2356 return;
2357 }
2358 asyncResp->res.jsonValue["@odata.type"] =
2359 "#LogService.v1_1_0.LogService";
2360 asyncResp->res.jsonValue["@odata.id"] =
2361 "/redfish/v1/Managers/bmc/LogServices/Journal";
2362 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2363 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2364 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2365 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302366
Ed Tanous002d39b2022-05-31 08:59:27 -07002367 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002368 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002369 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2370 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2371 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302372
Ed Tanous002d39b2022-05-31 08:59:27 -07002373 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2374 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2375 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002376}
Jason M. Billse1f26342018-07-18 12:12:00 -07002377
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002378static int
2379 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2380 sd_journal* journal,
2381 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002382{
2383 // Get the Log Entry contents
2384 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002385
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002386 std::string message;
2387 std::string_view syslogID;
2388 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2389 if (ret < 0)
2390 {
2391 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2392 << strerror(-ret);
2393 }
2394 if (!syslogID.empty())
2395 {
2396 message += std::string(syslogID) + ": ";
2397 }
2398
Ed Tanous39e77502019-03-04 17:35:53 -08002399 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002400 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002401 if (ret < 0)
2402 {
2403 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2404 return 1;
2405 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002406 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002407
2408 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002409 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002410 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002411 if (ret < 0)
2412 {
2413 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002414 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002415
2416 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002417 std::string entryTimeStr;
2418 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002419 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002420 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002421 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002422
2423 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002424 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002425 bmcJournalLogEntryJson["@odata.id"] =
2426 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2427 bmcJournalLogEntryID;
2428 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2429 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2430 bmcJournalLogEntryJson["Message"] = std::move(message);
2431 bmcJournalLogEntryJson["EntryType"] = "Oem";
2432 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2433 : severity <= 4 ? "Warning"
2434 : "OK";
2435 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2436 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002437 return 0;
2438}
2439
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002440inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002441{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002442 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002443 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002444 .methods(boost::beast::http::verb::get)(
2445 [&app](const crow::Request& req,
2446 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2447 query_param::QueryCapabilities capabilities = {
2448 .canDelegateTop = true,
2449 .canDelegateSkip = true,
2450 };
2451 query_param::Query delegatedQuery;
2452 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002453 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002454 {
2455 return;
2456 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002457
2458 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002459 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002460
Ed Tanous002d39b2022-05-31 08:59:27 -07002461 // Collections don't include the static data added by SubRoute
2462 // because it has a duplicate entry for members
2463 asyncResp->res.jsonValue["@odata.type"] =
2464 "#LogEntryCollection.LogEntryCollection";
2465 asyncResp->res.jsonValue["@odata.id"] =
2466 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2467 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2468 asyncResp->res.jsonValue["Description"] =
2469 "Collection of BMC Journal Entries";
2470 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2471 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002472
Ed Tanous002d39b2022-05-31 08:59:27 -07002473 // Go through the journal and use the timestamp to create a
2474 // unique ID for each entry
2475 sd_journal* journalTmp = nullptr;
2476 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2477 if (ret < 0)
2478 {
2479 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2480 messages::internalError(asyncResp->res);
2481 return;
2482 }
2483 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2484 journalTmp, sd_journal_close);
2485 journalTmp = nullptr;
2486 uint64_t entryCount = 0;
2487 // Reset the unique ID on the first entry
2488 bool firstEntry = true;
2489 SD_JOURNAL_FOREACH(journal.get())
2490 {
2491 entryCount++;
2492 // Handle paging using skip (number of entries to skip from
2493 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002494 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002495 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002496 continue;
2497 }
2498
2499 std::string idStr;
2500 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2501 {
2502 continue;
2503 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002504 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002505
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002506 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002507 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2508 bmcJournalLogEntry) != 0)
2509 {
George Liu0fda0f12021-11-16 10:06:17 +08002510 messages::internalError(asyncResp->res);
2511 return;
2512 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002513 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002514 }
2515 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002516 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002517 {
2518 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2519 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002520 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002521 }
George Liu0fda0f12021-11-16 10:06:17 +08002522 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002523}
Jason M. Billse1f26342018-07-18 12:12:00 -07002524
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002525inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002526{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002527 BMCWEB_ROUTE(app,
2528 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002529 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002530 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002531 [&app](const crow::Request& req,
2532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2533 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002534 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002535 {
2536 return;
2537 }
2538 // Convert the unique ID back to a timestamp to find the entry
2539 uint64_t ts = 0;
2540 uint64_t index = 0;
2541 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2542 {
2543 return;
2544 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002545
Ed Tanous002d39b2022-05-31 08:59:27 -07002546 sd_journal* journalTmp = nullptr;
2547 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2548 if (ret < 0)
2549 {
2550 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2551 messages::internalError(asyncResp->res);
2552 return;
2553 }
2554 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2555 journalTmp, sd_journal_close);
2556 journalTmp = nullptr;
2557 // Go to the timestamp in the log and move to the entry at the
2558 // index tracking the unique ID
2559 std::string idStr;
2560 bool firstEntry = true;
2561 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2562 if (ret < 0)
2563 {
2564 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2565 << strerror(-ret);
2566 messages::internalError(asyncResp->res);
2567 return;
2568 }
2569 for (uint64_t i = 0; i <= index; i++)
2570 {
2571 sd_journal_next(journal.get());
2572 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2573 {
2574 messages::internalError(asyncResp->res);
2575 return;
2576 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002577 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002578 }
2579 // Confirm that the entry ID matches what was requested
2580 if (idStr != entryID)
2581 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002582 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002583 return;
2584 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002585
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002586 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002587 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002588 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002589 {
2590 messages::internalError(asyncResp->res);
2591 return;
2592 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002593 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002594 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002595}
2596
Claire Weinanfdd26902022-03-01 14:18:25 -08002597inline void
2598 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2599 const std::string& dumpType)
2600{
2601 std::string dumpPath;
2602 std::string overWritePolicy;
2603 bool collectDiagnosticDataSupported = false;
2604
2605 if (dumpType == "BMC")
2606 {
2607 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2608 overWritePolicy = "WrapsWhenFull";
2609 collectDiagnosticDataSupported = true;
2610 }
2611 else if (dumpType == "FaultLog")
2612 {
2613 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2614 overWritePolicy = "Unknown";
2615 collectDiagnosticDataSupported = false;
2616 }
2617 else if (dumpType == "System")
2618 {
2619 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2620 overWritePolicy = "WrapsWhenFull";
2621 collectDiagnosticDataSupported = true;
2622 }
2623 else
2624 {
2625 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2626 << dumpType;
2627 messages::internalError(asyncResp->res);
2628 return;
2629 }
2630
2631 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2632 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2633 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2634 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2635 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2636 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2637
2638 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002639 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002640 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2641 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2642 redfishDateTimeOffset.second;
2643
2644 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2645 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2646 dumpPath + "/Actions/LogService.ClearLog";
2647
2648 if (collectDiagnosticDataSupported)
2649 {
2650 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2651 ["target"] =
2652 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2653 }
2654}
2655
2656inline void handleLogServicesDumpServiceGet(
2657 crow::App& app, const std::string& dumpType, const crow::Request& req,
2658 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2659{
2660 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2661 {
2662 return;
2663 }
2664 getDumpServiceInfo(asyncResp, dumpType);
2665}
2666
Ed Tanous22d268c2022-05-19 09:39:07 -07002667inline void handleLogServicesDumpServiceComputerSystemGet(
2668 crow::App& app, const crow::Request& req,
2669 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2670 const std::string& chassisId)
2671{
2672 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2673 {
2674 return;
2675 }
2676 if (chassisId != "system")
2677 {
2678 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2679 return;
2680 }
2681 getDumpServiceInfo(asyncResp, "System");
2682}
2683
Claire Weinanfdd26902022-03-01 14:18:25 -08002684inline void handleLogServicesDumpEntriesCollectionGet(
2685 crow::App& app, const std::string& dumpType, const crow::Request& req,
2686 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2687{
2688 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2689 {
2690 return;
2691 }
2692 getDumpEntryCollection(asyncResp, dumpType);
2693}
2694
Ed Tanous22d268c2022-05-19 09:39:07 -07002695inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2696 crow::App& app, const crow::Request& req,
2697 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2698 const std::string& chassisId)
2699{
2700 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2701 {
2702 return;
2703 }
2704 if (chassisId != "system")
2705 {
2706 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2707 return;
2708 }
2709 getDumpEntryCollection(asyncResp, "System");
2710}
2711
Claire Weinanfdd26902022-03-01 14:18:25 -08002712inline void handleLogServicesDumpEntryGet(
2713 crow::App& app, const std::string& dumpType, const crow::Request& req,
2714 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2715 const std::string& dumpId)
2716{
2717 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2718 {
2719 return;
2720 }
2721 getDumpEntryById(asyncResp, dumpId, dumpType);
2722}
Ed Tanous22d268c2022-05-19 09:39:07 -07002723inline void handleLogServicesDumpEntryComputerSystemGet(
2724 crow::App& app, const crow::Request& req,
2725 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2726 const std::string& chassisId, const std::string& dumpId)
2727{
2728 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2729 {
2730 return;
2731 }
2732 if (chassisId != "system")
2733 {
2734 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2735 return;
2736 }
2737 getDumpEntryById(asyncResp, dumpId, "System");
2738}
Claire Weinanfdd26902022-03-01 14:18:25 -08002739
2740inline void handleLogServicesDumpEntryDelete(
2741 crow::App& app, const std::string& dumpType, const crow::Request& req,
2742 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2743 const std::string& dumpId)
2744{
2745 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2746 {
2747 return;
2748 }
2749 deleteDumpEntry(asyncResp, dumpId, dumpType);
2750}
2751
Ed Tanous22d268c2022-05-19 09:39:07 -07002752inline void handleLogServicesDumpEntryComputerSystemDelete(
2753 crow::App& app, const crow::Request& req,
2754 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2755 const std::string& chassisId, const std::string& dumpId)
2756{
2757 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2758 {
2759 return;
2760 }
2761 if (chassisId != "system")
2762 {
2763 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2764 return;
2765 }
2766 deleteDumpEntry(asyncResp, dumpId, "System");
2767}
2768
Claire Weinanfdd26902022-03-01 14:18:25 -08002769inline void handleLogServicesDumpCollectDiagnosticDataPost(
2770 crow::App& app, const std::string& dumpType, const crow::Request& req,
2771 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2772{
2773 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2774 {
2775 return;
2776 }
2777 createDump(asyncResp, req, dumpType);
2778}
2779
Ed Tanous22d268c2022-05-19 09:39:07 -07002780inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2781 crow::App& app, const crow::Request& req,
2782 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2783 const std::string& chassisId)
2784{
2785 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2786 {
2787 return;
2788 }
2789 if (chassisId != "system")
2790 {
2791 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2792 return;
2793 }
2794 createDump(asyncResp, req, "System");
2795}
2796
Claire Weinanfdd26902022-03-01 14:18:25 -08002797inline void handleLogServicesDumpClearLogPost(
2798 crow::App& app, const std::string& dumpType, const crow::Request& req,
2799 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2800{
2801 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2802 {
2803 return;
2804 }
2805 clearDump(asyncResp, dumpType);
2806}
2807
Ed Tanous22d268c2022-05-19 09:39:07 -07002808inline void handleLogServicesDumpClearLogComputerSystemPost(
2809 crow::App& app, const crow::Request& req,
2810 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2811 const std::string& chassisId)
2812{
2813 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2814 {
2815 return;
2816 }
2817 if (chassisId != "system")
2818 {
2819 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2820 return;
2821 }
2822 clearDump(asyncResp, "System");
2823}
2824
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002825inline void requestRoutesBMCDumpService(App& app)
2826{
2827 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002828 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002829 .methods(boost::beast::http::verb::get)(std::bind_front(
2830 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002831}
2832
2833inline void requestRoutesBMCDumpEntryCollection(App& app)
2834{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002835 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002836 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002837 .methods(boost::beast::http::verb::get)(std::bind_front(
2838 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002839}
2840
2841inline void requestRoutesBMCDumpEntry(App& app)
2842{
2843 BMCWEB_ROUTE(app,
2844 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002845 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002846 .methods(boost::beast::http::verb::get)(std::bind_front(
2847 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2848
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002849 BMCWEB_ROUTE(app,
2850 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002851 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002852 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2853 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002854}
2855
2856inline void requestRoutesBMCDumpCreate(App& app)
2857{
George Liu0fda0f12021-11-16 10:06:17 +08002858 BMCWEB_ROUTE(
2859 app,
2860 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002861 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002862 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002863 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2864 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002865}
2866
2867inline void requestRoutesBMCDumpClear(App& app)
2868{
George Liu0fda0f12021-11-16 10:06:17 +08002869 BMCWEB_ROUTE(
2870 app,
2871 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002872 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002873 .methods(boost::beast::http::verb::post)(std::bind_front(
2874 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2875}
2876
2877inline void requestRoutesFaultLogDumpService(App& app)
2878{
2879 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2880 .privileges(redfish::privileges::getLogService)
2881 .methods(boost::beast::http::verb::get)(std::bind_front(
2882 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2883}
2884
2885inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2886{
2887 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2888 .privileges(redfish::privileges::getLogEntryCollection)
2889 .methods(boost::beast::http::verb::get)(
2890 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2891 std::ref(app), "FaultLog"));
2892}
2893
2894inline void requestRoutesFaultLogDumpEntry(App& app)
2895{
2896 BMCWEB_ROUTE(app,
2897 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2898 .privileges(redfish::privileges::getLogEntry)
2899 .methods(boost::beast::http::verb::get)(std::bind_front(
2900 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2901
2902 BMCWEB_ROUTE(app,
2903 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2904 .privileges(redfish::privileges::deleteLogEntry)
2905 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2906 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2907}
2908
2909inline void requestRoutesFaultLogDumpClear(App& app)
2910{
2911 BMCWEB_ROUTE(
2912 app,
2913 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2914 .privileges(redfish::privileges::postLogService)
2915 .methods(boost::beast::http::verb::post)(std::bind_front(
2916 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002917}
2918
2919inline void requestRoutesSystemDumpService(App& app)
2920{
Ed Tanous22d268c2022-05-19 09:39:07 -07002921 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002922 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002923 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002924 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002925}
2926
2927inline void requestRoutesSystemDumpEntryCollection(App& app)
2928{
Ed Tanous22d268c2022-05-19 09:39:07 -07002929 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002930 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002931 .methods(boost::beast::http::verb::get)(std::bind_front(
2932 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2933 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002934}
2935
2936inline void requestRoutesSystemDumpEntry(App& app)
2937{
2938 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002939 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002940 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002941 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002942 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002943
2944 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002945 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002946 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002947 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002948 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002949}
2950
2951inline void requestRoutesSystemDumpCreate(App& app)
2952{
George Liu0fda0f12021-11-16 10:06:17 +08002953 BMCWEB_ROUTE(
2954 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002955 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002956 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002957 .methods(boost::beast::http::verb::post)(std::bind_front(
2958 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2959 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002960}
2961
2962inline void requestRoutesSystemDumpClear(App& app)
2963{
George Liu0fda0f12021-11-16 10:06:17 +08002964 BMCWEB_ROUTE(
2965 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002966 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002967 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002968 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002969 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002970}
2971
2972inline void requestRoutesCrashdumpService(App& app)
2973{
2974 // Note: Deviated from redfish privilege registry for GET & HEAD
2975 // method for security reasons.
2976 /**
2977 * Functions triggers appropriate requests on DBus
2978 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002979 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002980 // This is incorrect, should be:
2981 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002982 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002983 .methods(boost::beast::http::verb::get)(
2984 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002985 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2986 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002987 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002988 {
2989 return;
2990 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002991 if (systemName != "system")
2992 {
2993 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2994 systemName);
2995 return;
2996 }
2997
Ed Tanous002d39b2022-05-31 08:59:27 -07002998 // Copy over the static data to include the entries added by
2999 // SubRoute
3000 asyncResp->res.jsonValue["@odata.id"] =
3001 "/redfish/v1/Systems/system/LogServices/Crashdump";
3002 asyncResp->res.jsonValue["@odata.type"] =
3003 "#LogService.v1_2_0.LogService";
3004 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
3005 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
3006 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
3007 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3008 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303009
Ed Tanous002d39b2022-05-31 08:59:27 -07003010 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003011 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003012 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3013 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3014 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303015
Ed Tanous002d39b2022-05-31 08:59:27 -07003016 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3017 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3018 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
3019 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
3020 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
3021 ["target"] =
3022 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003023 });
3024}
3025
3026void inline requestRoutesCrashdumpClear(App& app)
3027{
George Liu0fda0f12021-11-16 10:06:17 +08003028 BMCWEB_ROUTE(
3029 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003030 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003031 // This is incorrect, should be:
3032 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003033 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003034 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003035 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003036 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3037 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003038 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003039 {
3040 return;
3041 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003042 if (systemName != "system")
3043 {
3044 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3045 systemName);
3046 return;
3047 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003048 crow::connections::systemBus->async_method_call(
3049 [asyncResp](const boost::system::error_code ec,
3050 const std::string&) {
3051 if (ec)
3052 {
3053 messages::internalError(asyncResp->res);
3054 return;
3055 }
3056 messages::success(asyncResp->res);
3057 },
3058 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
3059 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003060}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003061
zhanghch058d1b46d2021-04-01 11:18:24 +08003062static void
3063 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3064 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003065{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003066 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003067 [asyncResp, logID,
3068 &logEntryJson](const boost::system::error_code ec,
3069 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003070 if (ec)
3071 {
3072 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3073 if (ec.value() ==
3074 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003075 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003076 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003077 }
3078 else
3079 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003080 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003081 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003082 return;
3083 }
3084
3085 std::string timestamp{};
3086 std::string filename{};
3087 std::string logfile{};
3088 parseCrashdumpParameters(params, filename, timestamp, logfile);
3089
3090 if (filename.empty() || timestamp.empty())
3091 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003092 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003093 return;
3094 }
3095
3096 std::string crashdumpURI =
3097 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3098 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003099 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003100 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003101 logEntry["@odata.id"] =
3102 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
3103 logEntry["Name"] = "CPU Crashdump";
3104 logEntry["Id"] = logID;
3105 logEntry["EntryType"] = "Oem";
3106 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3107 logEntry["DiagnosticDataType"] = "OEM";
3108 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3109 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003110
3111 // If logEntryJson references an array of LogEntry resources
3112 // ('Members' list), then push this as a new entry, otherwise set it
3113 // directly
3114 if (logEntryJson.is_array())
3115 {
3116 logEntryJson.push_back(logEntry);
3117 asyncResp->res.jsonValue["Members@odata.count"] =
3118 logEntryJson.size();
3119 }
3120 else
3121 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003122 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003123 }
3124 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003125 sdbusplus::asio::getAllProperties(
3126 *crow::connections::systemBus, crashdumpObject,
3127 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3128 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003129}
3130
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003131inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003132{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003133 // Note: Deviated from redfish privilege registry for GET & HEAD
3134 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003135 /**
3136 * Functions triggers appropriate requests on DBus
3137 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003138 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003139 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003140 // This is incorrect, should be.
3141 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003142 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003143 .methods(boost::beast::http::verb::get)(
3144 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003145 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3146 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003147 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003148 {
3149 return;
3150 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003151 if (systemName != "system")
3152 {
3153 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3154 systemName);
3155 return;
3156 }
3157
Ed Tanous002d39b2022-05-31 08:59:27 -07003158 crow::connections::systemBus->async_method_call(
3159 [asyncResp](const boost::system::error_code ec,
3160 const std::vector<std::string>& resp) {
3161 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003162 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003163 if (ec.value() !=
3164 boost::system::errc::no_such_file_or_directory)
3165 {
3166 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3167 << ec.message();
3168 messages::internalError(asyncResp->res);
3169 return;
3170 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003171 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003172 asyncResp->res.jsonValue["@odata.type"] =
3173 "#LogEntryCollection.LogEntryCollection";
3174 asyncResp->res.jsonValue["@odata.id"] =
3175 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3176 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3177 asyncResp->res.jsonValue["Description"] =
3178 "Collection of Crashdump Entries";
3179 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3180 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003181
Ed Tanous002d39b2022-05-31 08:59:27 -07003182 for (const std::string& path : resp)
3183 {
3184 const sdbusplus::message::object_path objPath(path);
3185 // Get the log ID
3186 std::string logID = objPath.filename();
3187 if (logID.empty())
3188 {
3189 continue;
3190 }
3191 // Add the log entry to the array
3192 logCrashdumpEntry(asyncResp, logID,
3193 asyncResp->res.jsonValue["Members"]);
3194 }
3195 },
3196 "xyz.openbmc_project.ObjectMapper",
3197 "/xyz/openbmc_project/object_mapper",
3198 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
3199 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003200 });
3201}
Ed Tanous1da66f72018-07-27 16:13:37 -07003202
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003203inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003204{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003205 // Note: Deviated from redfish privilege registry for GET & HEAD
3206 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003207
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003208 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003209 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003210 // this is incorrect, should be
3211 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003212 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003213 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003214 [&app](const crow::Request& req,
3215 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003216 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003217 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003218 {
3219 return;
3220 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003221 if (systemName != "system")
3222 {
3223 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3224 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003225 return;
3226 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003227 const std::string& logID = param;
3228 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3229 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003230}
Ed Tanous1da66f72018-07-27 16:13:37 -07003231
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003232inline void requestRoutesCrashdumpFile(App& app)
3233{
3234 // Note: Deviated from redfish privilege registry for GET & HEAD
3235 // method for security reasons.
3236 BMCWEB_ROUTE(
3237 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003238 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003239 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003240 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003241 [](const crow::Request& req,
3242 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003243 const std::string& systemName, const std::string& logID,
3244 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003245 // Do not call getRedfishRoute here since the crashdump file is not a
3246 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003247
3248 if (systemName != "system")
3249 {
3250 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3251 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003252 return;
3253 }
3254
Ed Tanous002d39b2022-05-31 08:59:27 -07003255 auto getStoredLogCallback =
3256 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3257 const boost::system::error_code ec,
3258 const std::vector<
3259 std::pair<std::string, dbus::utility::DbusVariantType>>&
3260 resp) {
3261 if (ec)
3262 {
3263 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3264 messages::internalError(asyncResp->res);
3265 return;
3266 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003267
Ed Tanous002d39b2022-05-31 08:59:27 -07003268 std::string dbusFilename{};
3269 std::string dbusTimestamp{};
3270 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003271
Ed Tanous002d39b2022-05-31 08:59:27 -07003272 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3273 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003274
Ed Tanous002d39b2022-05-31 08:59:27 -07003275 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3276 dbusFilepath.empty())
3277 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003278 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003279 return;
3280 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003281
Ed Tanous002d39b2022-05-31 08:59:27 -07003282 // Verify the file name parameter is correct
3283 if (fileName != dbusFilename)
3284 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003285 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003286 return;
3287 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003288
Ed Tanous002d39b2022-05-31 08:59:27 -07003289 if (!std::filesystem::exists(dbusFilepath))
3290 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003291 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003292 return;
3293 }
3294 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3295 asyncResp->res.body() =
3296 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003297
Ed Tanous002d39b2022-05-31 08:59:27 -07003298 // Configure this to be a file download when accessed
3299 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003300 asyncResp->res.addHeader(
3301 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003302 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003303 sdbusplus::asio::getAllProperties(
3304 *crow::connections::systemBus, crashdumpObject,
3305 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3306 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003307 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003308}
3309
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003310enum class OEMDiagnosticType
3311{
3312 onDemand,
3313 telemetry,
3314 invalid,
3315};
3316
Ed Tanousf7725d72022-03-07 12:46:00 -08003317inline OEMDiagnosticType
3318 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003319{
3320 if (oemDiagStr == "OnDemand")
3321 {
3322 return OEMDiagnosticType::onDemand;
3323 }
3324 if (oemDiagStr == "Telemetry")
3325 {
3326 return OEMDiagnosticType::telemetry;
3327 }
3328
3329 return OEMDiagnosticType::invalid;
3330}
3331
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003332inline void requestRoutesCrashdumpCollect(App& app)
3333{
3334 // Note: Deviated from redfish privilege registry for GET & HEAD
3335 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003336 BMCWEB_ROUTE(
3337 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003338 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003339 // The below is incorrect; Should be ConfigureManager
3340 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003341 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003342 .methods(boost::beast::http::verb::post)(
3343 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003344 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3345 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003346 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003347 {
3348 return;
3349 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003350
3351 if (systemName != "system")
3352 {
3353 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3354 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003355 return;
3356 }
3357
Ed Tanous002d39b2022-05-31 08:59:27 -07003358 std::string diagnosticDataType;
3359 std::string oemDiagnosticDataType;
3360 if (!redfish::json_util::readJsonAction(
3361 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3362 "OEMDiagnosticDataType", oemDiagnosticDataType))
3363 {
3364 return;
3365 }
3366
3367 if (diagnosticDataType != "OEM")
3368 {
3369 BMCWEB_LOG_ERROR
3370 << "Only OEM DiagnosticDataType supported for Crashdump";
3371 messages::actionParameterValueFormatError(
3372 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3373 "CollectDiagnosticData");
3374 return;
3375 }
3376
3377 OEMDiagnosticType oemDiagType =
3378 getOEMDiagnosticType(oemDiagnosticDataType);
3379
3380 std::string iface;
3381 std::string method;
3382 std::string taskMatchStr;
3383 if (oemDiagType == OEMDiagnosticType::onDemand)
3384 {
3385 iface = crashdumpOnDemandInterface;
3386 method = "GenerateOnDemandLog";
3387 taskMatchStr = "type='signal',"
3388 "interface='org.freedesktop.DBus.Properties',"
3389 "member='PropertiesChanged',"
3390 "arg0namespace='com.intel.crashdump'";
3391 }
3392 else if (oemDiagType == OEMDiagnosticType::telemetry)
3393 {
3394 iface = crashdumpTelemetryInterface;
3395 method = "GenerateTelemetryLog";
3396 taskMatchStr = "type='signal',"
3397 "interface='org.freedesktop.DBus.Properties',"
3398 "member='PropertiesChanged',"
3399 "arg0namespace='com.intel.crashdump'";
3400 }
3401 else
3402 {
3403 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3404 << oemDiagnosticDataType;
3405 messages::actionParameterValueFormatError(
3406 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3407 "CollectDiagnosticData");
3408 return;
3409 }
3410
3411 auto collectCrashdumpCallback =
3412 [asyncResp, payload(task::Payload(req)),
3413 taskMatchStr](const boost::system::error_code ec,
3414 const std::string&) mutable {
3415 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003416 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003417 if (ec.value() == boost::system::errc::operation_not_supported)
3418 {
3419 messages::resourceInStandby(asyncResp->res);
3420 }
3421 else if (ec.value() ==
3422 boost::system::errc::device_or_resource_busy)
3423 {
3424 messages::serviceTemporarilyUnavailable(asyncResp->res,
3425 "60");
3426 }
3427 else
3428 {
3429 messages::internalError(asyncResp->res);
3430 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003431 return;
3432 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003433 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003434 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003435 const std::shared_ptr<task::TaskData>& taskData) {
3436 if (!err)
3437 {
3438 taskData->messages.emplace_back(messages::taskCompletedOK(
3439 std::to_string(taskData->index)));
3440 taskData->state = "Completed";
3441 }
3442 return task::completed;
3443 },
3444 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003445
Ed Tanous002d39b2022-05-31 08:59:27 -07003446 task->startTimer(std::chrono::minutes(5));
3447 task->populateResp(asyncResp->res);
3448 task->payload.emplace(std::move(payload));
3449 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003450
Ed Tanous002d39b2022-05-31 08:59:27 -07003451 crow::connections::systemBus->async_method_call(
3452 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3453 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003454 });
3455}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003456
Andrew Geisslercb92c032018-08-17 07:56:14 -07003457/**
3458 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3459 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003460inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003461{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003462 /**
3463 * Function handles POST method request.
3464 * The Clear Log actions does not require any parameter.The action deletes
3465 * all entries found in the Entries collection for this Log Service.
3466 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003467
George Liu0fda0f12021-11-16 10:06:17 +08003468 BMCWEB_ROUTE(
3469 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003470 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003471 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003472 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003473 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003474 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3475 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003476 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003477 {
3478 return;
3479 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003480 if (systemName != "system")
3481 {
3482 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3483 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003484 return;
3485 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003486 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003487
Ed Tanous002d39b2022-05-31 08:59:27 -07003488 // Process response from Logging service.
3489 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3490 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3491 if (ec)
3492 {
3493 // TODO Handle for specific error code
3494 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3495 asyncResp->res.result(
3496 boost::beast::http::status::internal_server_error);
3497 return;
3498 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003499
Ed Tanous002d39b2022-05-31 08:59:27 -07003500 asyncResp->res.result(boost::beast::http::status::no_content);
3501 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003502
Ed Tanous002d39b2022-05-31 08:59:27 -07003503 // Make call to Logging service to request Clear Log
3504 crow::connections::systemBus->async_method_call(
3505 respHandler, "xyz.openbmc_project.Logging",
3506 "/xyz/openbmc_project/logging",
3507 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3508 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003509}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003510
3511/****************************************************
3512 * Redfish PostCode interfaces
3513 * using DBUS interface: getPostCodesTS
3514 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003515inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003516{
Ed Tanous22d268c2022-05-19 09:39:07 -07003517 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003518 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003519 .methods(boost::beast::http::verb::get)(
3520 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003521 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3522 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003523 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003524 {
3525 return;
3526 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003527 if (systemName != "system")
3528 {
3529 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3530 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003531 return;
3532 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003533 asyncResp->res.jsonValue["@odata.id"] =
3534 "/redfish/v1/Systems/system/LogServices/PostCodes";
3535 asyncResp->res.jsonValue["@odata.type"] =
3536 "#LogService.v1_1_0.LogService";
3537 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3538 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3539 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3540 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3541 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3542 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303543
Ed Tanous002d39b2022-05-31 08:59:27 -07003544 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003545 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003546 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3547 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3548 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303549
Ed Tanous002d39b2022-05-31 08:59:27 -07003550 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3551 {"target",
3552 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003553 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003554}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003555
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003556inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003557{
George Liu0fda0f12021-11-16 10:06:17 +08003558 BMCWEB_ROUTE(
3559 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003560 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003561 // The following privilege is incorrect; It should be ConfigureManager
3562 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003563 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003564 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003565 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003566 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3567 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003568 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003569 {
3570 return;
3571 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003572 if (systemName != "system")
3573 {
3574 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3575 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003576 return;
3577 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003578 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003579
Ed Tanous002d39b2022-05-31 08:59:27 -07003580 // Make call to post-code service to request clear all
3581 crow::connections::systemBus->async_method_call(
3582 [asyncResp](const boost::system::error_code ec) {
3583 if (ec)
3584 {
3585 // TODO Handle for specific error code
3586 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3587 << ec;
3588 asyncResp->res.result(
3589 boost::beast::http::status::internal_server_error);
3590 messages::internalError(asyncResp->res);
3591 return;
3592 }
3593 },
3594 "xyz.openbmc_project.State.Boot.PostCode0",
3595 "/xyz/openbmc_project/State/Boot/PostCode0",
3596 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3597 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003598}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003599
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003600/**
3601 * @brief Parse post code ID and get the current value and index value
3602 * eg: postCodeID=B1-2, currentValue=1, index=2
3603 *
3604 * @param[in] postCodeID Post Code ID
3605 * @param[out] currentValue Current value
3606 * @param[out] index Index value
3607 *
3608 * @return bool true if the parsing is successful, false the parsing fails
3609 */
3610inline static bool parsePostCode(const std::string& postCodeID,
3611 uint64_t& currentValue, uint16_t& index)
3612{
3613 std::vector<std::string> split;
3614 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3615 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3616 {
3617 return false;
3618 }
3619
3620 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3621 const char* start = split[0].data() + 1;
3622 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3623 const char* end = split[0].data() + split[0].size();
3624 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3625
3626 if (ptrIndex != end || ecIndex != std::errc())
3627 {
3628 return false;
3629 }
3630
3631 start = split[1].data();
3632
3633 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3634 end = split[1].data() + split[1].size();
3635 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
3636
3637 return ptrValue == end && ecValue == std::errc();
3638}
3639
3640static bool fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003641 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303642 const boost::container::flat_map<
3643 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003644 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3645 const uint64_t skip = 0, const uint64_t top = 0)
3646{
3647 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003648 const registries::Message* message =
3649 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003650
3651 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003652 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303653 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3654 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003655 {
3656 currentCodeIndex++;
3657 std::string postcodeEntryID =
3658 "B" + std::to_string(bootIndex) + "-" +
3659 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3660
3661 uint64_t usecSinceEpoch = code.first;
3662 uint64_t usTimeOffset = 0;
3663
3664 if (1 == currentCodeIndex)
3665 { // already incremented
3666 firstCodeTimeUs = code.first;
3667 }
3668 else
3669 {
3670 usTimeOffset = code.first - firstCodeTimeUs;
3671 }
3672
3673 // skip if no specific codeIndex is specified and currentCodeIndex does
3674 // not fall between top and skip
3675 if ((codeIndex == 0) &&
3676 (currentCodeIndex <= skip || currentCodeIndex > top))
3677 {
3678 continue;
3679 }
3680
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003681 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003682 // currentIndex
3683 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3684 {
3685 // This is done for simplicity. 1st entry is needed to calculate
3686 // time offset. To improve efficiency, one can get to the entry
3687 // directly (possibly with flatmap's nth method)
3688 continue;
3689 }
3690
3691 // currentCodeIndex is within top and skip or equal to specified code
3692 // index
3693
3694 // Get the Created time from the timestamp
3695 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003696 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003697 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003698
3699 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3700 std::ostringstream hexCode;
3701 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303702 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003703 std::ostringstream timeOffsetStr;
3704 // Set Fixed -Point Notation
3705 timeOffsetStr << std::fixed;
3706 // Set precision to 4 digits
3707 timeOffsetStr << std::setprecision(4);
3708 // Add double to stream
3709 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3710 std::vector<std::string> messageArgs = {
3711 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3712
3713 // Get MessageArgs template from message registry
3714 std::string msg;
3715 if (message != nullptr)
3716 {
3717 msg = message->message;
3718
3719 // fill in this post code value
3720 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003721 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003722 {
3723 std::string argStr = "%" + std::to_string(++i);
3724 size_t argPos = msg.find(argStr);
3725 if (argPos != std::string::npos)
3726 {
3727 msg.replace(argPos, argStr.length(), messageArg);
3728 }
3729 }
3730 }
3731
Tim Leed4342a92020-04-27 11:47:58 +08003732 // Get Severity template from message registry
3733 std::string severity;
3734 if (message != nullptr)
3735 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003736 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003737 }
3738
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003739 // Format entry
3740 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003741 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003742 bmcLogEntry["@odata.id"] =
3743 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3744 postcodeEntryID;
3745 bmcLogEntry["Name"] = "POST Code Log Entry";
3746 bmcLogEntry["Id"] = postcodeEntryID;
3747 bmcLogEntry["Message"] = std::move(msg);
3748 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3749 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3750 bmcLogEntry["EntryType"] = "Event";
3751 bmcLogEntry["Severity"] = std::move(severity);
3752 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003753 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3754 {
3755 bmcLogEntry["AdditionalDataURI"] =
3756 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3757 postcodeEntryID + "/attachment";
3758 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003759
3760 // codeIndex is only specified when querying single entry, return only
3761 // that entry in this case
3762 if (codeIndex != 0)
3763 {
3764 aResp->res.jsonValue.update(bmcLogEntry);
3765 return true;
3766 }
3767
3768 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
3769 logEntryArray.push_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08003770 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003771
3772 // Return value is always false when querying multiple entries
3773 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003774}
3775
zhanghch058d1b46d2021-04-01 11:18:24 +08003776static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003777 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003778{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003779 uint16_t bootIndex = 0;
3780 uint64_t codeIndex = 0;
3781 if (!parsePostCode(entryId, codeIndex, bootIndex))
3782 {
3783 // Requested ID was not found
3784 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3785 return;
3786 }
3787
3788 if (bootIndex == 0 || codeIndex == 0)
3789 {
3790 // 0 is an invalid index
3791 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3792 return;
3793 }
3794
ZhikuiRena3316fc2020-01-29 14:58:08 -08003795 crow::connections::systemBus->async_method_call(
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003796 [aResp, entryId, bootIndex,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303797 codeIndex](const boost::system::error_code ec,
3798 const boost::container::flat_map<
3799 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3800 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003801 if (ec)
3802 {
3803 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3804 messages::internalError(aResp->res);
3805 return;
3806 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003807
Ed Tanous002d39b2022-05-31 08:59:27 -07003808 if (postcode.empty())
3809 {
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003810 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07003811 return;
3812 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003813
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003814 if (!fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex))
3815 {
3816 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3817 return;
3818 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003819 },
Jonathan Doman15124762021-01-07 17:54:17 -08003820 "xyz.openbmc_project.State.Boot.PostCode0",
3821 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003822 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3823 bootIndex);
3824}
3825
zhanghch058d1b46d2021-04-01 11:18:24 +08003826static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003827 const uint16_t bootIndex,
3828 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003829 const uint64_t entryCount, size_t skip,
3830 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003831{
3832 crow::connections::systemBus->async_method_call(
3833 [aResp, bootIndex, bootCount, entryCount, skip,
3834 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303835 const boost::container::flat_map<
3836 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3837 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003838 if (ec)
3839 {
3840 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3841 messages::internalError(aResp->res);
3842 return;
3843 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003844
Ed Tanous002d39b2022-05-31 08:59:27 -07003845 uint64_t endCount = entryCount;
3846 if (!postcode.empty())
3847 {
3848 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003849 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003850 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003851 uint64_t thisBootSkip =
3852 std::max(static_cast<uint64_t>(skip), entryCount) -
3853 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003854 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003855 std::min(static_cast<uint64_t>(top + skip), endCount) -
3856 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003857
3858 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3859 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003860 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003861 aResp->res.jsonValue["Members@odata.count"] = endCount;
3862 }
3863
3864 // continue to previous bootIndex
3865 if (bootIndex < bootCount)
3866 {
3867 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3868 bootCount, endCount, skip, top);
3869 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003870 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003871 {
3872 aResp->res.jsonValue["Members@odata.nextLink"] =
3873 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3874 std::to_string(skip + top);
3875 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003876 },
Jonathan Doman15124762021-01-07 17:54:17 -08003877 "xyz.openbmc_project.State.Boot.PostCode0",
3878 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003879 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3880 bootIndex);
3881}
3882
zhanghch058d1b46d2021-04-01 11:18:24 +08003883static void
3884 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003885 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003886{
3887 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003888 sdbusplus::asio::getProperty<uint16_t>(
3889 *crow::connections::systemBus,
3890 "xyz.openbmc_project.State.Boot.PostCode0",
3891 "/xyz/openbmc_project/State/Boot/PostCode0",
3892 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3893 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3894 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003895 if (ec)
3896 {
3897 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3898 messages::internalError(aResp->res);
3899 return;
3900 }
3901 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003902 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003903}
3904
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003905inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003906{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003907 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003908 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003909 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003910 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003911 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003912 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3913 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003914 query_param::QueryCapabilities capabilities = {
3915 .canDelegateTop = true,
3916 .canDelegateSkip = true,
3917 };
3918 query_param::Query delegatedQuery;
3919 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003920 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003921 {
3922 return;
3923 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003924
3925 if (systemName != "system")
3926 {
3927 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3928 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003929 return;
3930 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003931 asyncResp->res.jsonValue["@odata.type"] =
3932 "#LogEntryCollection.LogEntryCollection";
3933 asyncResp->res.jsonValue["@odata.id"] =
3934 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3935 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3936 asyncResp->res.jsonValue["Description"] =
3937 "Collection of POST Code Log Entries";
3938 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3939 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003940 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003941 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003942 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003943 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003944}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003945
George Liu647b3cd2021-07-05 12:43:56 +08003946inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3947{
George Liu0fda0f12021-11-16 10:06:17 +08003948 BMCWEB_ROUTE(
3949 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003950 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003951 .privileges(redfish::privileges::getLogEntry)
3952 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003953 [&app](const crow::Request& req,
3954 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003955 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003956 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003957 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003958 {
3959 return;
3960 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003961 if (http_helpers::isContentTypeAllowed(
3962 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003963 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003964 {
3965 asyncResp->res.result(boost::beast::http::status::bad_request);
3966 return;
3967 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003968 if (systemName != "system")
3969 {
3970 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3971 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003972 return;
3973 }
George Liu647b3cd2021-07-05 12:43:56 +08003974
Ed Tanous002d39b2022-05-31 08:59:27 -07003975 uint64_t currentValue = 0;
3976 uint16_t index = 0;
3977 if (!parsePostCode(postCodeID, currentValue, index))
3978 {
3979 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3980 return;
3981 }
George Liu647b3cd2021-07-05 12:43:56 +08003982
Ed Tanous002d39b2022-05-31 08:59:27 -07003983 crow::connections::systemBus->async_method_call(
3984 [asyncResp, postCodeID, currentValue](
3985 const boost::system::error_code ec,
3986 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3987 postcodes) {
3988 if (ec.value() == EBADR)
3989 {
3990 messages::resourceNotFound(asyncResp->res, "LogEntry",
3991 postCodeID);
3992 return;
3993 }
3994 if (ec)
3995 {
3996 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3997 messages::internalError(asyncResp->res);
3998 return;
3999 }
George Liu647b3cd2021-07-05 12:43:56 +08004000
Ed Tanous002d39b2022-05-31 08:59:27 -07004001 size_t value = static_cast<size_t>(currentValue) - 1;
4002 if (value == std::string::npos || postcodes.size() < currentValue)
4003 {
4004 BMCWEB_LOG_ERROR << "Wrong currentValue value";
4005 messages::resourceNotFound(asyncResp->res, "LogEntry",
4006 postCodeID);
4007 return;
4008 }
George Liu647b3cd2021-07-05 12:43:56 +08004009
Ed Tanous002d39b2022-05-31 08:59:27 -07004010 const auto& [tID, c] = postcodes[value];
4011 if (c.empty())
4012 {
4013 BMCWEB_LOG_INFO << "No found post code data";
4014 messages::resourceNotFound(asyncResp->res, "LogEntry",
4015 postCodeID);
4016 return;
4017 }
4018 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4019 const char* d = reinterpret_cast<const char*>(c.data());
4020 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004021
Ed Tanousd9f6c622022-03-17 09:12:17 -07004022 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004023 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004024 asyncResp->res.addHeader(
4025 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07004026 asyncResp->res.body() = crow::utility::base64encode(strData);
4027 },
4028 "xyz.openbmc_project.State.Boot.PostCode0",
4029 "/xyz/openbmc_project/State/Boot/PostCode0",
4030 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
4031 });
George Liu647b3cd2021-07-05 12:43:56 +08004032}
4033
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004034inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004035{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004036 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004037 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004038 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004039 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004040 [&app](const crow::Request& req,
4041 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004042 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004043 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004044 {
4045 return;
4046 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004047 if (systemName != "system")
4048 {
4049 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4050 systemName);
4051 return;
4052 }
4053
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004054 getPostCodeForEntry(asyncResp, targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07004055 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004056}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004057
Ed Tanous1da66f72018-07-27 16:13:37 -07004058} // namespace redfish