blob: 09b2155021a1ceca30781a58f6a221bbfa7453ea [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
George Liu7a1dbc42022-12-07 16:03:22 +080018#include "dbus_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080019#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080020#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080021#include "human_sort.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070022#include "registries.hpp"
23#include "registries/base_message_registry.hpp"
24#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080025#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070026
Jason M. Billse1f26342018-07-18 12:12:00 -070027#include <systemd/sd-journal.h>
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060028#include <tinyxml2.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060029#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070030
John Edward Broadbent7e860f12021-04-08 15:57:16 -070031#include <app.hpp>
Ed Tanous9896eae2022-07-23 15:07:33 -070032#include <boost/algorithm/string/case_conv.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070033#include <boost/algorithm/string/classification.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060034#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070035#include <boost/algorithm/string/split.hpp>
Ed Tanous07c8c202022-07-11 10:08:08 -070036#include <boost/beast/http/verb.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070037#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080038#include <boost/system/linux_error.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 Liu7a1dbc42022-12-07 16:03:22 +080047#include <array>
George Liu647b3cd2021-07-05 12:43:56 +080048#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070049#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080050#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070051#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070052#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080053#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070054
55namespace redfish
56{
57
Gunnar Mills1214b7e2020-06-04 10:11:30 -050058constexpr char const* crashdumpObject = "com.intel.crashdump";
59constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050060constexpr char const* crashdumpInterface = "com.intel.crashdump";
61constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070062 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050063constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070064 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070065constexpr char const* crashdumpTelemetryInterface =
66 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070067
Asmitha Karunanithi8e317782020-12-10 03:35:05 -060068enum class DumpCreationProgress
69{
70 DUMP_CREATE_SUCCESS,
71 DUMP_CREATE_FAILED,
72 DUMP_CREATE_INPROGRESS
73};
74
Ed Tanousfffb8c12022-02-07 23:53:03 -080075namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070076{
Ed Tanous26702d02021-11-03 15:02:33 -070077static const Message*
78 getMessageFromRegistry(const std::string& messageKey,
79 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070080{
Ed Tanous002d39b2022-05-31 08:59:27 -070081 std::span<const MessageEntry>::iterator messageIt =
82 std::find_if(registry.begin(), registry.end(),
83 [&messageKey](const MessageEntry& messageEntry) {
84 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070085 });
86 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070087 {
88 return &messageIt->second;
89 }
90
91 return nullptr;
92}
93
Gunnar Mills1214b7e2020-06-04 10:11:30 -050094static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070095{
96 // Redfish MessageIds are in the form
97 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
98 // the right Message
99 std::vector<std::string> fields;
100 fields.reserve(4);
101 boost::split(fields, messageID, boost::is_any_of("."));
Ed Tanous02cad962022-06-30 16:50:15 -0700102 const std::string& registryName = fields[0];
103 const std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -0700104
105 // Find the right registry and check it for the MessageKey
106 if (std::string(base::header.registryPrefix) == registryName)
107 {
108 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700109 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700110 }
111 if (std::string(openbmc::header.registryPrefix) == registryName)
112 {
113 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700114 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700115 }
116 return nullptr;
117}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800118} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700119
James Feistf6150402019-01-08 10:36:20 -0800120namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700121
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500122inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700123{
Ed Tanousd4d25792020-09-29 15:15:03 -0700124 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
125 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
126 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
127 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700128 {
129 return "Critical";
130 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700131 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
132 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
133 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700134 {
135 return "OK";
136 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700137 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700138 {
139 return "Warning";
140 }
141 return "";
142}
143
Abhishek Patel9017faf2021-09-14 22:48:55 -0500144inline std::optional<bool> getProviderNotifyAction(const std::string& notify)
145{
146 std::optional<bool> notifyAction;
147 if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Notify")
148 {
149 notifyAction = true;
150 }
151 else if (notify == "xyz.openbmc_project.Logging.Entry.Notify.Inhibit")
152 {
153 notifyAction = false;
154 }
155
156 return notifyAction;
157}
158
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700159inline static int getJournalMetadata(sd_journal* journal,
160 const std::string_view& field,
161 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700162{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700164 size_t length = 0;
165 int ret = 0;
166 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800167 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
168 const void** dataVoid = reinterpret_cast<const void**>(&data);
169
170 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700171 if (ret < 0)
172 {
173 return ret;
174 }
Ed Tanous39e77502019-03-04 17:35:53 -0800175 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700176 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000177 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700178 return ret;
179}
180
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700181inline static int getJournalMetadata(sd_journal* journal,
182 const std::string_view& field,
183 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700184{
185 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800186 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700187 // Get the metadata from the requested field of the journal entry
188 ret = getJournalMetadata(journal, field, metadata);
189 if (ret < 0)
190 {
191 return ret;
192 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000193 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700194 return ret;
195}
196
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700197inline static bool getEntryTimestamp(sd_journal* journal,
198 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800199{
200 int ret = 0;
201 uint64_t timestamp = 0;
202 ret = sd_journal_get_realtime_usec(journal, &timestamp);
203 if (ret < 0)
204 {
205 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
206 << strerror(-ret);
207 return false;
208 }
Ed Tanous2b829372022-08-03 14:22:34 -0700209 entryTimestamp =
210 redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500211 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800212}
Ed Tanous50b8a432022-02-03 16:29:50 -0800213
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700214inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
215 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700216{
217 int ret = 0;
218 static uint64_t prevTs = 0;
219 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700220 if (firstEntry)
221 {
222 prevTs = 0;
223 }
224
Jason M. Bills16428a12018-11-02 12:42:29 -0700225 // Get the entry timestamp
226 uint64_t curTs = 0;
227 ret = sd_journal_get_realtime_usec(journal, &curTs);
228 if (ret < 0)
229 {
230 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
231 << strerror(-ret);
232 return false;
233 }
234 // If the timestamp isn't unique, increment the index
235 if (curTs == prevTs)
236 {
237 index++;
238 }
239 else
240 {
241 // Otherwise, reset it
242 index = 0;
243 }
244 // Save the timestamp
245 prevTs = curTs;
246
247 entryID = std::to_string(curTs);
248 if (index > 0)
249 {
250 entryID += "_" + std::to_string(index);
251 }
252 return true;
253}
254
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500255static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700256 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700257{
Ed Tanous271584a2019-07-09 16:24:22 -0700258 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700259 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700260 if (firstEntry)
261 {
262 prevTs = 0;
263 }
264
Jason M. Bills95820182019-04-22 16:25:34 -0700265 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700266 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700267 std::tm timeStruct = {};
268 std::istringstream entryStream(logEntry);
269 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
270 {
271 curTs = std::mktime(&timeStruct);
272 }
273 // If the timestamp isn't unique, increment the index
274 if (curTs == prevTs)
275 {
276 index++;
277 }
278 else
279 {
280 // Otherwise, reset it
281 index = 0;
282 }
283 // Save the timestamp
284 prevTs = curTs;
285
286 entryID = std::to_string(curTs);
287 if (index > 0)
288 {
289 entryID += "_" + std::to_string(index);
290 }
291 return true;
292}
293
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700294inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800295 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
296 const std::string& entryID, uint64_t& timestamp,
297 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700298{
299 if (entryID.empty())
300 {
301 return false;
302 }
303 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800304 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700305
Ed Tanous81ce6092020-12-17 16:54:55 +0000306 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800307 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700308 {
309 // Timestamp has an index
310 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800311 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700312 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700313 auto [ptr, ec] = std::from_chars(
314 indexStr.data(), indexStr.data() + indexStr.size(), index);
315 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700316 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800317 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700318 return false;
319 }
320 }
321 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700322 auto [ptr, ec] =
323 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
324 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700325 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800326 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700327 return false;
328 }
329 return true;
330}
331
Jason M. Bills95820182019-04-22 16:25:34 -0700332static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500333 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700334{
335 static const std::filesystem::path redfishLogDir = "/var/log";
336 static const std::string redfishLogFilename = "redfish";
337
338 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500339 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700340 std::filesystem::directory_iterator(redfishLogDir))
341 {
342 // If we find a redfish log file, save the path
343 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700344 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700345 {
346 redfishLogFiles.emplace_back(redfishLogDir / filename);
347 }
348 }
349 // As the log files rotate, they are appended with a ".#" that is higher for
350 // the older logs. Since we don't expect more than 10 log files, we
351 // can just sort the list to get them in order from newest to oldest
352 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
353
354 return !redfishLogFiles.empty();
355}
356
Claire Weinanaefe3782022-07-15 19:17:19 -0700357inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800358 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700359 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700360 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
361{
362 for (const auto& interfaceMap : object.second)
363 {
364 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
365 {
366 for (const auto& propertyMap : interfaceMap.second)
367 {
368 if (propertyMap.first == "Status")
369 {
370 const auto* status =
371 std::get_if<std::string>(&propertyMap.second);
372 if (status == nullptr)
373 {
374 messages::internalError(asyncResp->res);
375 break;
376 }
377 dumpStatus = *status;
378 }
379 }
380 }
381 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
382 {
383 for (const auto& propertyMap : interfaceMap.second)
384 {
385 if (propertyMap.first == "Size")
386 {
387 const auto* sizePtr =
388 std::get_if<uint64_t>(&propertyMap.second);
389 if (sizePtr == nullptr)
390 {
391 messages::internalError(asyncResp->res);
392 break;
393 }
394 size = *sizePtr;
395 break;
396 }
397 }
398 }
399 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
400 {
401 for (const auto& propertyMap : interfaceMap.second)
402 {
403 if (propertyMap.first == "Elapsed")
404 {
405 const uint64_t* usecsTimeStamp =
406 std::get_if<uint64_t>(&propertyMap.second);
407 if (usecsTimeStamp == nullptr)
408 {
409 messages::internalError(asyncResp->res);
410 break;
411 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700412 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700413 break;
414 }
415 }
416 }
417 }
418}
419
Nan Zhou21ab4042022-06-26 23:07:40 +0000420static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800421{
422 std::string entriesPath;
423
424 if (dumpType == "BMC")
425 {
426 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
427 }
428 else if (dumpType == "FaultLog")
429 {
430 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
431 }
432 else if (dumpType == "System")
433 {
434 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
435 }
436 else
437 {
438 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
439 << dumpType;
440 }
441
442 // Returns empty string on error
443 return entriesPath;
444}
445
zhanghch058d1b46d2021-04-01 11:18:24 +0800446inline void
447 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
448 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500449{
Claire Weinanfdd26902022-03-01 14:18:25 -0800450 std::string entriesPath = getDumpEntriesPath(dumpType);
451 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500452 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500453 messages::internalError(asyncResp->res);
454 return;
455 }
456
457 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800458 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800459 dumpType](const boost::system::error_code ec,
460 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700461 if (ec)
462 {
463 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
464 messages::internalError(asyncResp->res);
465 return;
466 }
467
Claire Weinanfdd26902022-03-01 14:18:25 -0800468 // Remove ending slash
469 std::string odataIdStr = entriesPath;
470 if (!odataIdStr.empty())
471 {
472 odataIdStr.pop_back();
473 }
474
475 asyncResp->res.jsonValue["@odata.type"] =
476 "#LogEntryCollection.LogEntryCollection";
477 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
478 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
479 asyncResp->res.jsonValue["Description"] =
480 "Collection of " + dumpType + " Dump Entries";
481
Ed Tanous002d39b2022-05-31 08:59:27 -0700482 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
483 entriesArray = nlohmann::json::array();
484 std::string dumpEntryPath =
485 "/xyz/openbmc_project/dump/" +
486 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
487
488 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
489 return AlphanumLess<std::string>()(l.first.filename(),
490 r.first.filename());
491 });
492
493 for (auto& object : resp)
494 {
495 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500496 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700497 continue;
498 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700499 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700500 uint64_t size = 0;
501 std::string dumpStatus;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700502 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700503
504 std::string entryID = object.first.filename();
505 if (entryID.empty())
506 {
507 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500508 }
509
Claire Weinanc6fecda2022-07-15 10:43:25 -0700510 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700511 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700512
513 if (dumpStatus !=
514 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
515 !dumpStatus.empty())
516 {
517 // Dump status is not Complete, no need to enumerate
518 continue;
519 }
520
Vijay Lobo9c11a172021-10-07 16:53:16 -0500521 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800522 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700523 thisEntry["Id"] = entryID;
524 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700525 thisEntry["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700526 thisEntry["Created"] =
527 redfish::time_utils::getDateTimeUintUs(timestampUs);
Ed Tanous002d39b2022-05-31 08:59:27 -0700528
Ed Tanous002d39b2022-05-31 08:59:27 -0700529 if (dumpType == "BMC")
530 {
531 thisEntry["DiagnosticDataType"] = "Manager";
532 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800533 entriesPath + entryID + "/attachment";
534 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 }
536 else if (dumpType == "System")
537 {
538 thisEntry["DiagnosticDataType"] = "OEM";
539 thisEntry["OEMDiagnosticDataType"] = "System";
540 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800541 entriesPath + entryID + "/attachment";
542 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700543 }
544 entriesArray.push_back(std::move(thisEntry));
545 }
546 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500547 },
548 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
549 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
550}
551
zhanghch058d1b46d2021-04-01 11:18:24 +0800552inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700553 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800554 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500555{
Claire Weinanfdd26902022-03-01 14:18:25 -0800556 std::string entriesPath = getDumpEntriesPath(dumpType);
557 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500558 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500559 messages::internalError(asyncResp->res);
560 return;
561 }
562
563 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800564 [asyncResp, entryID, dumpType,
565 entriesPath](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700566 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700567 if (ec)
568 {
569 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
570 messages::internalError(asyncResp->res);
571 return;
572 }
573
574 bool foundDumpEntry = false;
575 std::string dumpEntryPath =
576 "/xyz/openbmc_project/dump/" +
577 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
578
579 for (const auto& objectPath : resp)
580 {
581 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500582 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700583 continue;
584 }
585
586 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700587 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700588 uint64_t size = 0;
589 std::string dumpStatus;
590
Claire Weinanaefe3782022-07-15 19:17:19 -0700591 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700592 timestampUs, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700593
594 if (dumpStatus !=
595 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
596 !dumpStatus.empty())
597 {
598 // Dump status is not Complete
599 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200600 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
601 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500602 return;
603 }
604
Ed Tanous002d39b2022-05-31 08:59:27 -0700605 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -0500606 "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800607 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700608 asyncResp->res.jsonValue["Id"] = entryID;
609 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700610 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Claire Weinanbbd80db2022-10-26 16:55:52 -0700611 asyncResp->res.jsonValue["Created"] =
612 redfish::time_utils::getDateTimeUintUs(timestampUs);
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500613
Ed Tanous002d39b2022-05-31 08:59:27 -0700614 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500615 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700616 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
617 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800618 entriesPath + entryID + "/attachment";
619 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500620 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700621 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500622 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700623 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
624 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
625 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800626 entriesPath + entryID + "/attachment";
627 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500628 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700629 }
630 if (!foundDumpEntry)
631 {
632 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
633 messages::internalError(asyncResp->res);
634 return;
635 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500636 },
637 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
638 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
639}
640
zhanghch058d1b46d2021-04-01 11:18:24 +0800641inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800642 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500643 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500644{
Ed Tanous002d39b2022-05-31 08:59:27 -0700645 auto respHandler =
646 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500647 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
648 if (ec)
649 {
George Liu3de8d8b2021-03-22 17:49:39 +0800650 if (ec.value() == EBADR)
651 {
652 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
653 return;
654 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500655 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800656 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500657 messages::internalError(asyncResp->res);
658 return;
659 }
660 };
661 crow::connections::systemBus->async_method_call(
662 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500663 "/xyz/openbmc_project/dump/" +
664 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
665 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500666 "xyz.openbmc_project.Object.Delete", "Delete");
667}
668
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600669inline DumpCreationProgress
670 mapDbusStatusToDumpProgress(const std::string& status)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500671{
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600672 if (status ==
673 "xyz.openbmc_project.Common.Progress.OperationStatus.Failed" ||
674 status == "xyz.openbmc_project.Common.Progress.OperationStatus.Aborted")
675 {
676 return DumpCreationProgress::DUMP_CREATE_FAILED;
677 }
678 if (status ==
679 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed")
680 {
681 return DumpCreationProgress::DUMP_CREATE_SUCCESS;
682 }
683 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
684}
685
686inline DumpCreationProgress
687 getDumpCompletionStatus(const dbus::utility::DBusPropertiesMap& values)
688{
689 for (const auto& [key, val] : values)
690 {
691 if (key == "Status")
Ed Tanous002d39b2022-05-31 08:59:27 -0700692 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600693 const std::string* value = std::get_if<std::string>(&val);
694 if (value == nullptr)
695 {
696 BMCWEB_LOG_ERROR << "Status property value is null";
697 return DumpCreationProgress::DUMP_CREATE_FAILED;
698 }
699 return mapDbusStatusToDumpProgress(*value);
700 }
701 }
702 return DumpCreationProgress::DUMP_CREATE_INPROGRESS;
703}
704
705inline std::string getDumpEntryPath(const std::string& dumpPath)
706{
707 if (dumpPath == "/xyz/openbmc_project/dump/bmc/entry")
708 {
709 return "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
710 }
711 if (dumpPath == "/xyz/openbmc_project/dump/system/entry")
712 {
713 return "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
714 }
715 return "";
716}
717
718inline void createDumpTaskCallback(
719 task::Payload&& payload,
720 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
721 const sdbusplus::message::object_path& createdObjPath)
722{
723 const std::string dumpPath = createdObjPath.parent_path().str;
724 const std::string dumpId = createdObjPath.filename();
725
726 std::string dumpEntryPath = getDumpEntryPath(dumpPath);
727
728 if (dumpEntryPath.empty())
729 {
730 BMCWEB_LOG_ERROR << "Invalid dump type received";
731 messages::internalError(asyncResp->res);
732 return;
733 }
734
735 crow::connections::systemBus->async_method_call(
736 [asyncResp, payload, createdObjPath,
737 dumpEntryPath{std::move(dumpEntryPath)},
738 dumpId](const boost::system::error_code ec,
739 const std::string& introspectXml) {
740 if (ec)
741 {
742 BMCWEB_LOG_ERROR << "Introspect call failed with error: "
743 << ec.message();
744 messages::internalError(asyncResp->res);
745 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700746 }
747
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600748 // Check if the created dump object has implemented Progress
749 // interface to track dump completion. If yes, fetch the "Status"
750 // property of the interface, modify the task state accordingly.
751 // Else, return task completed.
752 tinyxml2::XMLDocument doc;
Ed Tanous002d39b2022-05-31 08:59:27 -0700753
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600754 doc.Parse(introspectXml.data(), introspectXml.size());
755 tinyxml2::XMLNode* pRoot = doc.FirstChildElement("node");
756 if (pRoot == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -0700757 {
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600758 BMCWEB_LOG_ERROR << "XML document failed to parse";
759 messages::internalError(asyncResp->res);
760 return;
761 }
762 tinyxml2::XMLElement* interfaceNode =
763 pRoot->FirstChildElement("interface");
764
765 bool isProgressIntfPresent = false;
766 while (interfaceNode != nullptr)
767 {
768 const char* thisInterfaceName = interfaceNode->Attribute("name");
769 if (thisInterfaceName != nullptr)
770 {
771 if (thisInterfaceName ==
772 std::string_view("xyz.openbmc_project.Common.Progress"))
773 {
774 interfaceNode =
775 interfaceNode->NextSiblingElement("interface");
776 continue;
777 }
778 isProgressIntfPresent = true;
779 break;
780 }
781 interfaceNode = interfaceNode->NextSiblingElement("interface");
782 }
783
784 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
785 [createdObjPath, dumpEntryPath, dumpId, isProgressIntfPresent](
Patrick Williams5b378542022-11-26 09:41:59 -0600786 boost::system::error_code err, sdbusplus::message_t& msg,
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600787 const std::shared_ptr<task::TaskData>& taskData) {
788 if (err)
789 {
790 BMCWEB_LOG_ERROR << createdObjPath.str
791 << ": Error in creating dump";
792 taskData->messages.emplace_back(messages::internalError());
793 taskData->state = "Cancelled";
794 return task::completed;
795 }
796
797 if (isProgressIntfPresent)
798 {
799 dbus::utility::DBusPropertiesMap values;
800 std::string prop;
801 msg.read(prop, values);
802
803 DumpCreationProgress dumpStatus =
804 getDumpCompletionStatus(values);
805 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_FAILED)
806 {
807 BMCWEB_LOG_ERROR << createdObjPath.str
808 << ": Error in creating dump";
809 taskData->state = "Cancelled";
810 return task::completed;
811 }
812
813 if (dumpStatus == DumpCreationProgress::DUMP_CREATE_INPROGRESS)
814 {
815 BMCWEB_LOG_DEBUG << createdObjPath.str
816 << ": Dump creation task is in progress";
817 return !task::completed;
818 }
819 }
820
Ed Tanous002d39b2022-05-31 08:59:27 -0700821 nlohmann::json retMessage = messages::success();
822 taskData->messages.emplace_back(retMessage);
823
824 std::string headerLoc =
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600825 "Location: " + dumpEntryPath + http_helpers::urlEncode(dumpId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700826 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
827
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600828 BMCWEB_LOG_DEBUG << createdObjPath.str
829 << ": Dump creation task completed";
Ed Tanous002d39b2022-05-31 08:59:27 -0700830 taskData->state = "Completed";
831 return task::completed;
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600832 },
833 "type='signal',interface='org.freedesktop.DBus.Properties',"
834 "member='PropertiesChanged',path='" +
835 createdObjPath.str + "'");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500836
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600837 // The task timer is set to max time limit within which the
838 // requested dump will be collected.
839 task->startTimer(std::chrono::minutes(6));
840 task->populateResp(asyncResp->res);
841 task->payload.emplace(payload);
842 },
843 "xyz.openbmc_project.Dump.Manager", createdObjPath,
844 "org.freedesktop.DBus.Introspectable", "Introspect");
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500845}
846
zhanghch058d1b46d2021-04-01 11:18:24 +0800847inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
848 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500849{
Claire Weinanfdd26902022-03-01 14:18:25 -0800850 std::string dumpPath = getDumpEntriesPath(dumpType);
851 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500852 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500853 messages::internalError(asyncResp->res);
854 return;
855 }
856
857 std::optional<std::string> diagnosticDataType;
858 std::optional<std::string> oemDiagnosticDataType;
859
Willy Tu15ed6782021-12-14 11:03:16 -0800860 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500861 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
862 "OEMDiagnosticDataType", oemDiagnosticDataType))
863 {
864 return;
865 }
866
867 if (dumpType == "System")
868 {
869 if (!oemDiagnosticDataType || !diagnosticDataType)
870 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800871 BMCWEB_LOG_ERROR
872 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500873 messages::actionParameterMissing(
874 asyncResp->res, "CollectDiagnosticData",
875 "DiagnosticDataType & OEMDiagnosticDataType");
876 return;
877 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700878 if ((*oemDiagnosticDataType != "System") ||
879 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500880 {
881 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700882 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500883 return;
884 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500885 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500886 }
887 else if (dumpType == "BMC")
888 {
889 if (!diagnosticDataType)
890 {
George Liu0fda0f12021-11-16 10:06:17 +0800891 BMCWEB_LOG_ERROR
892 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500893 messages::actionParameterMissing(
894 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
895 return;
896 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700897 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500898 {
899 BMCWEB_LOG_ERROR
900 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700901 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500902 return;
903 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500904 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
905 }
906 else
907 {
908 BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type";
909 messages::internalError(asyncResp->res);
910 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500911 }
912
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600913 std::vector<std::pair<std::string, std::variant<std::string, uint64_t>>>
914 createDumpParamVec;
915
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500916 crow::connections::systemBus->async_method_call(
Patrick Williams5b378542022-11-26 09:41:59 -0600917 [asyncResp, payload(task::Payload(req)), dumpPath](
918 const boost::system::error_code ec, const sdbusplus::message_t& msg,
919 const sdbusplus::message::object_path& objPath) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 if (ec)
921 {
922 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500923 const sd_bus_error* dbusError = msg.get_error();
924 if (dbusError == nullptr)
925 {
926 messages::internalError(asyncResp->res);
927 return;
928 }
929
930 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
931 << " and error msg: " << dbusError->message;
932 if (std::string_view(
933 "xyz.openbmc_project.Common.Error.NotAllowed") ==
934 dbusError->name)
935 {
936 messages::resourceInStandby(asyncResp->res);
937 return;
938 }
939 if (std::string_view(
940 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
941 dbusError->name)
942 {
943 messages::serviceDisabled(asyncResp->res, dumpPath);
944 return;
945 }
946 if (std::string_view(
947 "xyz.openbmc_project.Common.Error.Unavailable") ==
948 dbusError->name)
949 {
950 messages::resourceInUse(asyncResp->res);
951 return;
952 }
953 // Other Dbus errors such as:
954 // xyz.openbmc_project.Common.Error.InvalidArgument &
955 // org.freedesktop.DBus.Error.InvalidArgs are all related to
956 // the dbus call that is made here in the bmcweb
957 // implementation and has nothing to do with the client's
958 // input in the request. Hence, returning internal error
959 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700960 messages::internalError(asyncResp->res);
961 return;
962 }
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600963 BMCWEB_LOG_DEBUG << "Dump Created. Path: " << objPath.str;
964 createDumpTaskCallback(std::move(payload), asyncResp, objPath);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500965 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500966 "xyz.openbmc_project.Dump.Manager",
967 "/xyz/openbmc_project/dump/" +
968 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithi8e317782020-12-10 03:35:05 -0600969 "xyz.openbmc_project.Dump.Create", "CreateDump", createDumpParamVec);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500970}
971
zhanghch058d1b46d2021-04-01 11:18:24 +0800972inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
973 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500974{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500975 std::string dumpTypeLowerCopy =
976 std::string(boost::algorithm::to_lower_copy(dumpType));
George Liu7a1dbc42022-12-07 16:03:22 +0800977 std::string interface = "xyz.openbmc_project.Dump.Entry." + dumpType;
978 const std::array<const std::string_view, 1> interfaces{interface};
zhanghch058d1b46d2021-04-01 11:18:24 +0800979
George Liu7a1dbc42022-12-07 16:03:22 +0800980 dbus::utility::getSubTreePaths(
981 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800982 [asyncResp, dumpType](
George Liu7a1dbc42022-12-07 16:03:22 +0800983 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800984 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700985 if (ec)
986 {
987 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
988 messages::internalError(asyncResp->res);
989 return;
990 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500991
Ed Tanous002d39b2022-05-31 08:59:27 -0700992 for (const std::string& path : subTreePaths)
993 {
994 sdbusplus::message::object_path objPath(path);
995 std::string logID = objPath.filename();
996 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500997 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700998 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500999 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001000 deleteDumpEntry(asyncResp, logID, dumpType);
1001 }
George Liu7a1dbc42022-12-07 16:03:22 +08001002 });
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05001003}
1004
Ed Tanousb9d36b42022-02-26 21:42:46 -08001005inline static void
1006 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
1007 std::string& filename, std::string& timestamp,
1008 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001009{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001010 const std::string* filenamePtr = nullptr;
1011 const std::string* timestampPtr = nullptr;
1012 const std::string* logfilePtr = nullptr;
1013
1014 const bool success = sdbusplus::unpackPropertiesNoThrow(
1015 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
1016 "Filename", filenamePtr, "Log", logfilePtr);
1017
1018 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -07001019 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001020 return;
1021 }
1022
1023 if (filenamePtr != nullptr)
1024 {
1025 filename = *filenamePtr;
1026 }
1027
1028 if (timestampPtr != nullptr)
1029 {
1030 timestamp = *timestampPtr;
1031 }
1032
1033 if (logfilePtr != nullptr)
1034 {
1035 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -07001036 }
1037}
1038
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001039inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07001040{
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001041 /**
1042 * Functions triggers appropriate requests on DBus
1043 */
Ed Tanous22d268c2022-05-19 09:39:07 -07001044 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -07001045 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001046 .methods(boost::beast::http::verb::get)(
1047 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001048 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1049 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001050 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001051 {
1052 return;
1053 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001054 if (systemName != "system")
1055 {
1056 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1057 systemName);
1058 return;
1059 }
1060
Ed Tanous002d39b2022-05-31 08:59:27 -07001061 // Collections don't include the static data added by SubRoute
1062 // because it has a duplicate entry for members
1063 asyncResp->res.jsonValue["@odata.type"] =
1064 "#LogServiceCollection.LogServiceCollection";
1065 asyncResp->res.jsonValue["@odata.id"] =
1066 "/redfish/v1/Systems/system/LogServices";
1067 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
1068 asyncResp->res.jsonValue["Description"] =
1069 "Collection of LogServices for this Computer System";
1070 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
1071 logServiceArray = nlohmann::json::array();
1072 nlohmann::json::object_t eventLog;
1073 eventLog["@odata.id"] =
1074 "/redfish/v1/Systems/system/LogServices/EventLog";
1075 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001076#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001077 nlohmann::json::object_t dumpLog;
1078 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
1079 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -06001080#endif
1081
Jason M. Billsd53dd412019-02-12 17:16:22 -08001082#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07001083 nlohmann::json::object_t crashdump;
1084 crashdump["@odata.id"] =
1085 "/redfish/v1/Systems/system/LogServices/Crashdump";
1086 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -08001087#endif
Spencer Kub7028eb2021-10-26 15:27:35 +08001088
1089#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -07001090 nlohmann::json::object_t hostlogger;
1091 hostlogger["@odata.id"] =
1092 "/redfish/v1/Systems/system/LogServices/HostLogger";
1093 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +08001094#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07001095 asyncResp->res.jsonValue["Members@odata.count"] =
1096 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08001097
George Liu7a1dbc42022-12-07 16:03:22 +08001098 constexpr std::array<std::string_view, 1> interfaces = {
1099 "xyz.openbmc_project.State.Boot.PostCode"};
1100 dbus::utility::getSubTreePaths(
1101 "/", 0, interfaces,
1102 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07001103 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 }
George Liu7a1dbc42022-12-07 16:03:22 +08001128 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001129 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001130}
1131
1132inline void requestRoutesEventLogService(App& app)
1133{
Ed Tanous22d268c2022-05-19 09:39:07 -07001134 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001135 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001136 .methods(boost::beast::http::verb::get)(
1137 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001138 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1139 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001140 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001141 {
1142 return;
1143 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001144 if (systemName != "system")
1145 {
1146 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1147 systemName);
1148 return;
1149 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001150 asyncResp->res.jsonValue["@odata.id"] =
1151 "/redfish/v1/Systems/system/LogServices/EventLog";
1152 asyncResp->res.jsonValue["@odata.type"] =
1153 "#LogService.v1_1_0.LogService";
1154 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1155 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1156 asyncResp->res.jsonValue["Id"] = "EventLog";
1157 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301158
Ed Tanous002d39b2022-05-31 08:59:27 -07001159 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001160 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301161
Ed Tanous002d39b2022-05-31 08:59:27 -07001162 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1163 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1164 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301165
Ed Tanous002d39b2022-05-31 08:59:27 -07001166 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1167 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1168 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001169
Ed Tanous002d39b2022-05-31 08:59:27 -07001170 {"target",
1171 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001172 });
1173}
1174
1175inline void requestRoutesJournalEventLogClear(App& app)
1176{
Jason M. Bills4978b632022-02-22 14:17:43 -08001177 BMCWEB_ROUTE(
1178 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001179 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001180 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001181 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001182 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001183 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1184 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001185 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001186 {
1187 return;
1188 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001189 if (systemName != "system")
1190 {
1191 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1192 systemName);
1193 return;
1194 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001195 // Clear the EventLog by deleting the log files
1196 std::vector<std::filesystem::path> redfishLogFiles;
1197 if (getRedfishLogFiles(redfishLogFiles))
1198 {
1199 for (const std::filesystem::path& file : redfishLogFiles)
1200 {
1201 std::error_code ec;
1202 std::filesystem::remove(file, ec);
1203 }
1204 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001205
Ed Tanous002d39b2022-05-31 08:59:27 -07001206 // Reload rsyslog so it knows to start new log files
1207 crow::connections::systemBus->async_method_call(
1208 [asyncResp](const boost::system::error_code ec) {
1209 if (ec)
1210 {
1211 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1212 messages::internalError(asyncResp->res);
1213 return;
1214 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001215
Ed Tanous002d39b2022-05-31 08:59:27 -07001216 messages::success(asyncResp->res);
1217 },
1218 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1219 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1220 "replace");
1221 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001222}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001223
Jason M. Billsac992cd2022-06-24 13:31:46 -07001224enum class LogParseError
1225{
1226 success,
1227 parseFailed,
1228 messageIdNotInRegistry,
1229};
1230
1231static LogParseError
1232 fillEventLogEntryJson(const std::string& logEntryID,
1233 const std::string& logEntry,
1234 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001235{
Jason M. Bills95820182019-04-22 16:25:34 -07001236 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001237 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001238 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001239 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001240 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001241 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001242 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001243 std::string timestamp = logEntry.substr(0, space);
1244 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001245 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001246 if (entryStart == std::string::npos)
1247 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001248 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001249 }
1250 std::string_view entry(logEntry);
1251 entry.remove_prefix(entryStart);
1252 // Use split to separate the entry into its fields
1253 std::vector<std::string> logEntryFields;
1254 boost::split(logEntryFields, entry, boost::is_any_of(","),
1255 boost::token_compress_on);
1256 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001257 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001258 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001259 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001260 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001261 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001262
Jason M. Bills4851d452019-03-28 11:27:48 -07001263 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001264 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001265
Sui Chen54417b02022-03-24 14:59:52 -07001266 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001267 {
Sui Chen54417b02022-03-24 14:59:52 -07001268 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001269 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001270 }
1271
Sui Chen54417b02022-03-24 14:59:52 -07001272 std::string msg = message->message;
1273
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001274 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001275 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001276 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001277 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001278 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001279 // If the first string is empty, assume there are no MessageArgs
1280 std::size_t messageArgsSize = 0;
1281 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001282 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001283 messageArgsSize = logEntryFields.size() - 1;
1284 }
1285
Ed Tanous23a21a12020-07-25 04:45:05 +00001286 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001287
1288 // Fill the MessageArgs into the Message
1289 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001290 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001291 {
1292 std::string argStr = "%" + std::to_string(++i);
1293 size_t argPos = msg.find(argStr);
1294 if (argPos != std::string::npos)
1295 {
1296 msg.replace(argPos, argStr.length(), messageArg);
1297 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001298 }
1299 }
1300
Jason M. Bills95820182019-04-22 16:25:34 -07001301 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1302 // format which matches the Redfish format except for the fractional seconds
1303 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001304 std::size_t dot = timestamp.find_first_of('.');
1305 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001306 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001307 {
Jason M. Bills95820182019-04-22 16:25:34 -07001308 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001309 }
1310
1311 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001312 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001313 logEntryJson["@odata.id"] =
1314 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1315 logEntryJson["Name"] = "System Event Log Entry";
1316 logEntryJson["Id"] = logEntryID;
1317 logEntryJson["Message"] = std::move(msg);
1318 logEntryJson["MessageId"] = std::move(messageID);
1319 logEntryJson["MessageArgs"] = messageArgs;
1320 logEntryJson["EntryType"] = "Event";
1321 logEntryJson["Severity"] = message->messageSeverity;
1322 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001323 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001324}
1325
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001326inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001327{
Ed Tanous22d268c2022-05-19 09:39:07 -07001328 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001329 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001330 .methods(boost::beast::http::verb::get)(
1331 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001332 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1333 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001334 query_param::QueryCapabilities capabilities = {
1335 .canDelegateTop = true,
1336 .canDelegateSkip = true,
1337 };
1338 query_param::Query delegatedQuery;
1339 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001340 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001341 {
1342 return;
1343 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001344 if (systemName != "system")
1345 {
1346 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1347 systemName);
1348 return;
1349 }
1350
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001351 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001352 size_t skip = delegatedQuery.skip.value_or(0);
1353
Ed Tanous002d39b2022-05-31 08:59:27 -07001354 // Collections don't include the static data added by SubRoute
1355 // because it has a duplicate entry for members
1356 asyncResp->res.jsonValue["@odata.type"] =
1357 "#LogEntryCollection.LogEntryCollection";
1358 asyncResp->res.jsonValue["@odata.id"] =
1359 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1360 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1361 asyncResp->res.jsonValue["Description"] =
1362 "Collection of System Event Log Entries";
1363
1364 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1365 logEntryArray = nlohmann::json::array();
1366 // Go through the log files and create a unique ID for each
1367 // entry
1368 std::vector<std::filesystem::path> redfishLogFiles;
1369 getRedfishLogFiles(redfishLogFiles);
1370 uint64_t entryCount = 0;
1371 std::string logEntry;
1372
1373 // Oldest logs are in the last file, so start there and loop
1374 // backwards
1375 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1376 it++)
1377 {
1378 std::ifstream logStream(*it);
1379 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001380 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001381 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001382 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001383
Ed Tanous002d39b2022-05-31 08:59:27 -07001384 // Reset the unique ID on the first entry
1385 bool firstEntry = true;
1386 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001387 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001388 std::string idStr;
1389 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001390 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001391 continue;
1392 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001393 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001394
Jason M. Billsde703c52022-06-23 14:19:04 -07001395 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001396 LogParseError status =
1397 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1398 if (status == LogParseError::messageIdNotInRegistry)
1399 {
1400 continue;
1401 }
1402 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001403 {
1404 messages::internalError(asyncResp->res);
1405 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001406 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001407
Jason M. Billsde703c52022-06-23 14:19:04 -07001408 entryCount++;
1409 // Handle paging using skip (number of entries to skip from the
1410 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001411 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001412 {
1413 continue;
1414 }
1415
1416 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001417 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001418 }
1419 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001420 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 {
1422 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1423 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001424 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001425 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001426 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001427}
Chicago Duan336e96c2019-07-15 14:22:08 +08001428
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001429inline void requestRoutesJournalEventLogEntry(App& app)
1430{
1431 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001432 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001433 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001434 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001435 [&app](const crow::Request& req,
1436 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001437 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001438 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001439 {
1440 return;
1441 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001442
1443 if (systemName != "system")
1444 {
1445 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1446 systemName);
1447 return;
1448 }
1449
Ed Tanous002d39b2022-05-31 08:59:27 -07001450 const std::string& targetID = param;
1451
1452 // Go through the log files and check the unique ID for each
1453 // entry to find the target entry
1454 std::vector<std::filesystem::path> redfishLogFiles;
1455 getRedfishLogFiles(redfishLogFiles);
1456 std::string logEntry;
1457
1458 // Oldest logs are in the last file, so start there and loop
1459 // backwards
1460 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1461 it++)
1462 {
1463 std::ifstream logStream(*it);
1464 if (!logStream.is_open())
1465 {
1466 continue;
1467 }
1468
1469 // Reset the unique ID on the first entry
1470 bool firstEntry = true;
1471 while (std::getline(logStream, logEntry))
1472 {
1473 std::string idStr;
1474 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001475 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001476 continue;
1477 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001478 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001479
1480 if (idStr == targetID)
1481 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001482 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001483 LogParseError status =
1484 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1485 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001486 {
1487 messages::internalError(asyncResp->res);
1488 return;
1489 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001490 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001491 return;
1492 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001493 }
1494 }
1495 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001496 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07001497 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001498}
1499
1500inline void requestRoutesDBusEventLogEntryCollection(App& app)
1501{
Ed Tanous22d268c2022-05-19 09:39:07 -07001502 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001503 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001504 .methods(boost::beast::http::verb::get)(
1505 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001506 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1507 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001508 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001509 {
1510 return;
1511 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001512 if (systemName != "system")
1513 {
1514 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1515 systemName);
1516 return;
1517 }
1518
Ed Tanous002d39b2022-05-31 08:59:27 -07001519 // Collections don't include the static data added by SubRoute
1520 // because it has a duplicate entry for members
1521 asyncResp->res.jsonValue["@odata.type"] =
1522 "#LogEntryCollection.LogEntryCollection";
1523 asyncResp->res.jsonValue["@odata.id"] =
1524 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1525 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1526 asyncResp->res.jsonValue["Description"] =
1527 "Collection of System Event Log Entries";
1528
1529 // DBus implementation of EventLog/Entries
1530 // Make call to Logging Service to find all log entry objects
1531 crow::connections::systemBus->async_method_call(
1532 [asyncResp](const boost::system::error_code ec,
1533 const dbus::utility::ManagedObjectType& resp) {
1534 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001535 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001536 // TODO Handle for specific error code
1537 BMCWEB_LOG_ERROR
1538 << "getLogEntriesIfaceData resp_handler got error " << ec;
1539 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001540 return;
1541 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001542 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1543 entriesArray = nlohmann::json::array();
1544 for (const auto& objectPath : resp)
1545 {
1546 const uint32_t* id = nullptr;
1547 const uint64_t* timestamp = nullptr;
1548 const uint64_t* updateTimestamp = nullptr;
1549 const std::string* severity = nullptr;
1550 const std::string* message = nullptr;
1551 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001552 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001553 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001554 const std::string* notify = nullptr;
1555
Ed Tanous002d39b2022-05-31 08:59:27 -07001556 for (const auto& interfaceMap : objectPath.second)
1557 {
1558 if (interfaceMap.first ==
1559 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001560 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001561 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001562 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001563 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001564 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001565 id = std::get_if<uint32_t>(&propertyMap.second);
1566 }
1567 else if (propertyMap.first == "Timestamp")
1568 {
1569 timestamp =
1570 std::get_if<uint64_t>(&propertyMap.second);
1571 }
1572 else if (propertyMap.first == "UpdateTimestamp")
1573 {
1574 updateTimestamp =
1575 std::get_if<uint64_t>(&propertyMap.second);
1576 }
1577 else if (propertyMap.first == "Severity")
1578 {
1579 severity = std::get_if<std::string>(
1580 &propertyMap.second);
1581 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001582 else if (propertyMap.first == "Resolution")
1583 {
1584 resolution = std::get_if<std::string>(
1585 &propertyMap.second);
1586 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001587 else if (propertyMap.first == "Message")
1588 {
1589 message = std::get_if<std::string>(
1590 &propertyMap.second);
1591 }
1592 else if (propertyMap.first == "Resolved")
1593 {
1594 const bool* resolveptr =
1595 std::get_if<bool>(&propertyMap.second);
1596 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001597 {
1598 messages::internalError(asyncResp->res);
1599 return;
1600 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001601 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001602 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001603 else if (propertyMap.first ==
1604 "ServiceProviderNotify")
1605 {
1606 notify = std::get_if<std::string>(
1607 &propertyMap.second);
1608 if (notify == nullptr)
1609 {
1610 messages::internalError(asyncResp->res);
1611 return;
1612 }
1613 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001614 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001615 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001616 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001617 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001618 messages::internalError(asyncResp->res);
1619 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001620 }
1621 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001622 else if (interfaceMap.first ==
1623 "xyz.openbmc_project.Common.FilePath")
1624 {
1625 for (const auto& propertyMap : interfaceMap.second)
1626 {
1627 if (propertyMap.first == "Path")
1628 {
1629 filePath = std::get_if<std::string>(
1630 &propertyMap.second);
1631 }
1632 }
1633 }
1634 }
1635 // Object path without the
1636 // xyz.openbmc_project.Logging.Entry interface, ignore
1637 // and continue.
1638 if (id == nullptr || message == nullptr ||
1639 severity == nullptr || timestamp == nullptr ||
1640 updateTimestamp == nullptr)
1641 {
1642 continue;
1643 }
1644 entriesArray.push_back({});
1645 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001646 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 thisEntry["@odata.id"] =
1648 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1649 std::to_string(*id);
1650 thisEntry["Name"] = "System Event Log Entry";
1651 thisEntry["Id"] = std::to_string(*id);
1652 thisEntry["Message"] = *message;
1653 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001654 if ((resolution != nullptr) && (!(*resolution).empty()))
1655 {
1656 thisEntry["Resolution"] = *resolution;
1657 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001658 std::optional<bool> notifyAction =
1659 getProviderNotifyAction(*notify);
1660 if (notifyAction)
1661 {
1662 thisEntry["ServiceProviderNotified"] = *notifyAction;
1663 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001664 thisEntry["EntryType"] = "Event";
1665 thisEntry["Severity"] =
1666 translateSeverityDbusToRedfish(*severity);
1667 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001668 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001669 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001670 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001671 if (filePath != nullptr)
1672 {
1673 thisEntry["AdditionalDataURI"] =
1674 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1675 std::to_string(*id) + "/attachment";
1676 }
1677 }
1678 std::sort(
1679 entriesArray.begin(), entriesArray.end(),
1680 [](const nlohmann::json& left, const nlohmann::json& right) {
1681 return (left["Id"] <= right["Id"]);
1682 });
1683 asyncResp->res.jsonValue["Members@odata.count"] =
1684 entriesArray.size();
1685 },
1686 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1687 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001688 });
1689}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001690
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001691inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001692{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001693 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001694 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001695 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001696 .methods(boost::beast::http::verb::get)(
1697 [&app](const crow::Request& req,
1698 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001699 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001700 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001701 {
1702 return;
1703 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001704 if (systemName != "system")
1705 {
1706 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1707 systemName);
1708 return;
1709 }
1710
Ed Tanous002d39b2022-05-31 08:59:27 -07001711 std::string entryID = param;
1712 dbus::utility::escapePathForDbus(entryID);
1713
1714 // DBus implementation of EventLog/Entries
1715 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001716 sdbusplus::asio::getAllProperties(
1717 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1718 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001719 [asyncResp, entryID](const boost::system::error_code ec,
1720 const dbus::utility::DBusPropertiesMap& resp) {
1721 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001722 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001723 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1724 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001725 return;
1726 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001727 if (ec)
1728 {
1729 BMCWEB_LOG_ERROR
1730 << "EventLogEntry (DBus) resp_handler got error " << ec;
1731 messages::internalError(asyncResp->res);
1732 return;
1733 }
1734 const uint32_t* id = nullptr;
1735 const uint64_t* timestamp = nullptr;
1736 const uint64_t* updateTimestamp = nullptr;
1737 const std::string* severity = nullptr;
1738 const std::string* message = nullptr;
1739 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001740 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001741 bool resolved = false;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001742 const std::string* notify = nullptr;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001743
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001744 const bool success = sdbusplus::unpackPropertiesNoThrow(
1745 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1746 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001747 severity, "Message", message, "Resolved", resolved,
Abhishek Patel9017faf2021-09-14 22:48:55 -05001748 "Resolution", resolution, "Path", filePath,
1749 "ServiceProviderNotify", notify);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001750
1751 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001752 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001753 messages::internalError(asyncResp->res);
1754 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001755 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001756
Ed Tanous002d39b2022-05-31 08:59:27 -07001757 if (id == nullptr || message == nullptr || severity == nullptr ||
Abhishek Patel9017faf2021-09-14 22:48:55 -05001758 timestamp == nullptr || updateTimestamp == nullptr ||
1759 notify == nullptr)
Ed Tanous002d39b2022-05-31 08:59:27 -07001760 {
1761 messages::internalError(asyncResp->res);
1762 return;
1763 }
Abhishek Patel9017faf2021-09-14 22:48:55 -05001764
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001766 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001767 asyncResp->res.jsonValue["@odata.id"] =
1768 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1769 std::to_string(*id);
1770 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1771 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1772 asyncResp->res.jsonValue["Message"] = *message;
1773 asyncResp->res.jsonValue["Resolved"] = resolved;
Abhishek Patel9017faf2021-09-14 22:48:55 -05001774 std::optional<bool> notifyAction = getProviderNotifyAction(*notify);
1775 if (notifyAction)
1776 {
1777 asyncResp->res.jsonValue["ServiceProviderNotified"] =
1778 *notifyAction;
1779 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001780 if ((resolution != nullptr) && (!(*resolution).empty()))
1781 {
1782 asyncResp->res.jsonValue["Resolution"] = *resolution;
1783 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001784 asyncResp->res.jsonValue["EntryType"] = "Event";
1785 asyncResp->res.jsonValue["Severity"] =
1786 translateSeverityDbusToRedfish(*severity);
1787 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001788 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001789 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001790 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001791 if (filePath != nullptr)
1792 {
1793 asyncResp->res.jsonValue["AdditionalDataURI"] =
1794 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1795 std::to_string(*id) + "/attachment";
1796 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001797 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001798 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001799
1800 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001801 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001802 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001803 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001804 [&app](const crow::Request& req,
1805 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001806 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001807 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001808 {
1809 return;
1810 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001811 if (systemName != "system")
1812 {
1813 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1814 systemName);
1815 return;
1816 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001817 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001818
Ed Tanous002d39b2022-05-31 08:59:27 -07001819 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1820 resolved))
1821 {
1822 return;
1823 }
1824 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001825
Ed Tanous002d39b2022-05-31 08:59:27 -07001826 crow::connections::systemBus->async_method_call(
1827 [asyncResp, entryId](const boost::system::error_code ec) {
1828 if (ec)
1829 {
1830 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1831 messages::internalError(asyncResp->res);
1832 return;
1833 }
1834 },
1835 "xyz.openbmc_project.Logging",
1836 "/xyz/openbmc_project/logging/entry/" + entryId,
1837 "org.freedesktop.DBus.Properties", "Set",
1838 "xyz.openbmc_project.Logging.Entry", "Resolved",
1839 dbus::utility::DbusVariantType(*resolved));
1840 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001841
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001842 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001843 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001844 .privileges(redfish::privileges::deleteLogEntry)
1845
Ed Tanous002d39b2022-05-31 08:59:27 -07001846 .methods(boost::beast::http::verb::delete_)(
1847 [&app](const crow::Request& req,
1848 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001849 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001850 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 {
1852 return;
1853 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001854 if (systemName != "system")
1855 {
1856 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1857 systemName);
1858 return;
1859 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001860 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1861
1862 std::string entryID = param;
1863
1864 dbus::utility::escapePathForDbus(entryID);
1865
1866 // Process response from Logging service.
1867 auto respHandler =
1868 [asyncResp, entryID](const boost::system::error_code ec) {
1869 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1870 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001871 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001872 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001873 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001874 messages::resourceNotFound(asyncResp->res, "LogEntry",
1875 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001876 return;
1877 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001878 // TODO Handle for specific error code
1879 BMCWEB_LOG_ERROR
1880 << "EventLogEntry (DBus) doDelete respHandler got error "
1881 << ec;
1882 asyncResp->res.result(
1883 boost::beast::http::status::internal_server_error);
1884 return;
1885 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001886
Ed Tanous002d39b2022-05-31 08:59:27 -07001887 asyncResp->res.result(boost::beast::http::status::ok);
1888 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001889
Ed Tanous002d39b2022-05-31 08:59:27 -07001890 // Make call to Logging service to request Delete Log
1891 crow::connections::systemBus->async_method_call(
1892 respHandler, "xyz.openbmc_project.Logging",
1893 "/xyz/openbmc_project/logging/entry/" + entryID,
1894 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001895 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001896}
1897
1898inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001899{
George Liu0fda0f12021-11-16 10:06:17 +08001900 BMCWEB_ROUTE(
1901 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001902 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001903 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001904 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001905 [&app](const crow::Request& req,
1906 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001907 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001908 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001909 {
1910 return;
1911 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001912 if (http_helpers::isContentTypeAllowed(
1913 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001914 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001915 {
1916 asyncResp->res.result(boost::beast::http::status::bad_request);
1917 return;
1918 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001919 if (systemName != "system")
1920 {
1921 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1922 systemName);
1923 return;
1924 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001925
Ed Tanous002d39b2022-05-31 08:59:27 -07001926 std::string entryID = param;
1927 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001928
Ed Tanous002d39b2022-05-31 08:59:27 -07001929 crow::connections::systemBus->async_method_call(
1930 [asyncResp, entryID](const boost::system::error_code ec,
1931 const sdbusplus::message::unix_fd& unixfd) {
1932 if (ec.value() == EBADR)
1933 {
1934 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1935 entryID);
1936 return;
1937 }
1938 if (ec)
1939 {
1940 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1941 messages::internalError(asyncResp->res);
1942 return;
1943 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001944
Ed Tanous002d39b2022-05-31 08:59:27 -07001945 int fd = -1;
1946 fd = dup(unixfd);
1947 if (fd == -1)
1948 {
1949 messages::internalError(asyncResp->res);
1950 return;
1951 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001952
Ed Tanous002d39b2022-05-31 08:59:27 -07001953 long long int size = lseek(fd, 0, SEEK_END);
1954 if (size == -1)
1955 {
1956 messages::internalError(asyncResp->res);
1957 return;
1958 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001959
Ed Tanous002d39b2022-05-31 08:59:27 -07001960 // Arbitrary max size of 64kb
1961 constexpr int maxFileSize = 65536;
1962 if (size > maxFileSize)
1963 {
1964 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1965 << maxFileSize;
1966 messages::internalError(asyncResp->res);
1967 return;
1968 }
1969 std::vector<char> data(static_cast<size_t>(size));
1970 long long int rc = lseek(fd, 0, SEEK_SET);
1971 if (rc == -1)
1972 {
1973 messages::internalError(asyncResp->res);
1974 return;
1975 }
1976 rc = read(fd, data.data(), data.size());
1977 if ((rc == -1) || (rc != size))
1978 {
1979 messages::internalError(asyncResp->res);
1980 return;
1981 }
1982 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001983
Ed Tanous002d39b2022-05-31 08:59:27 -07001984 std::string_view strData(data.data(), data.size());
1985 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001986
Ed Tanousd9f6c622022-03-17 09:12:17 -07001987 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001988 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001989 asyncResp->res.addHeader(
1990 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001991 asyncResp->res.body() = std::move(output);
1992 },
1993 "xyz.openbmc_project.Logging",
1994 "/xyz/openbmc_project/logging/entry/" + entryID,
1995 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1996 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001997}
1998
Spencer Kub7028eb2021-10-26 15:27:35 +08001999constexpr const char* hostLoggerFolderPath = "/var/log/console";
2000
2001inline bool
2002 getHostLoggerFiles(const std::string& hostLoggerFilePath,
2003 std::vector<std::filesystem::path>& hostLoggerFiles)
2004{
2005 std::error_code ec;
2006 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
2007 if (ec)
2008 {
2009 BMCWEB_LOG_ERROR << ec.message();
2010 return false;
2011 }
2012 for (const std::filesystem::directory_entry& it : logPath)
2013 {
2014 std::string filename = it.path().filename();
2015 // Prefix of each log files is "log". Find the file and save the
2016 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07002017 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08002018 {
2019 hostLoggerFiles.emplace_back(it.path());
2020 }
2021 }
2022 // As the log files rotate, they are appended with a ".#" that is higher for
2023 // the older logs. Since we start from oldest logs, sort the name in
2024 // descending order.
2025 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
2026 AlphanumLess<std::string>());
2027
2028 return true;
2029}
2030
Ed Tanous02cad962022-06-30 16:50:15 -07002031inline bool getHostLoggerEntries(
2032 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
2033 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08002034{
2035 GzFileReader logFile;
2036
2037 // Go though all log files and expose host logs.
2038 for (const std::filesystem::path& it : hostLoggerFiles)
2039 {
2040 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
2041 {
2042 BMCWEB_LOG_ERROR << "fail to expose host logs";
2043 return false;
2044 }
2045 }
2046 // Get lastMessage from constructor by getter
2047 std::string lastMessage = logFile.getLastMessage();
2048 if (!lastMessage.empty())
2049 {
2050 logCount++;
2051 if (logCount > skip && logCount <= (skip + top))
2052 {
2053 logEntries.push_back(lastMessage);
2054 }
2055 }
2056 return true;
2057}
2058
2059inline void fillHostLoggerEntryJson(const std::string& logEntryID,
2060 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002061 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08002062{
2063 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05002064 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002065 logEntryJson["@odata.id"] =
2066 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
2067 logEntryID;
2068 logEntryJson["Name"] = "Host Logger Entry";
2069 logEntryJson["Id"] = logEntryID;
2070 logEntryJson["Message"] = msg;
2071 logEntryJson["EntryType"] = "Oem";
2072 logEntryJson["Severity"] = "OK";
2073 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08002074}
2075
2076inline void requestRoutesSystemHostLogger(App& app)
2077{
Ed Tanous22d268c2022-05-19 09:39:07 -07002078 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002079 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07002080 .methods(boost::beast::http::verb::get)(
2081 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002082 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2083 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002084 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002085 {
2086 return;
2087 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002088 if (systemName != "system")
2089 {
2090 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2091 systemName);
2092 return;
2093 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002094 asyncResp->res.jsonValue["@odata.id"] =
2095 "/redfish/v1/Systems/system/LogServices/HostLogger";
2096 asyncResp->res.jsonValue["@odata.type"] =
2097 "#LogService.v1_1_0.LogService";
2098 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
2099 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
2100 asyncResp->res.jsonValue["Id"] = "HostLogger";
2101 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2102 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2103 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002104}
2105
2106inline void requestRoutesSystemHostLoggerCollection(App& app)
2107{
2108 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002109 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002110 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07002111 .methods(boost::beast::http::verb::get)(
2112 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2114 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002115 query_param::QueryCapabilities capabilities = {
2116 .canDelegateTop = true,
2117 .canDelegateSkip = true,
2118 };
2119 query_param::Query delegatedQuery;
2120 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002121 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002122 {
2123 return;
2124 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002125 if (systemName != "system")
2126 {
2127 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2128 systemName);
2129 return;
2130 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002131 asyncResp->res.jsonValue["@odata.id"] =
2132 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
2133 asyncResp->res.jsonValue["@odata.type"] =
2134 "#LogEntryCollection.LogEntryCollection";
2135 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
2136 asyncResp->res.jsonValue["Description"] =
2137 "Collection of HostLogger Entries";
2138 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2139 logEntryArray = nlohmann::json::array();
2140 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08002141
Ed Tanous002d39b2022-05-31 08:59:27 -07002142 std::vector<std::filesystem::path> hostLoggerFiles;
2143 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2144 {
2145 BMCWEB_LOG_ERROR << "fail to get host log file path";
2146 return;
2147 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002148 // If we weren't provided top and skip limits, use the defaults.
2149 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002150 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07002151 size_t logCount = 0;
2152 // This vector only store the entries we want to expose that
2153 // control by skip and top.
2154 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002155 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
2156 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07002157 {
2158 messages::internalError(asyncResp->res);
2159 return;
2160 }
2161 // If vector is empty, that means skip value larger than total
2162 // log count
2163 if (logEntries.empty())
2164 {
2165 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2166 return;
2167 }
2168 if (!logEntries.empty())
2169 {
2170 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002171 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002172 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002173 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2174 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002175 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002176 }
2177
Ed Tanous002d39b2022-05-31 08:59:27 -07002178 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002179 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002180 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002181 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2182 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002183 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002184 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 }
George Liu0fda0f12021-11-16 10:06:17 +08002186 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002187}
2188
2189inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2190{
2191 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002192 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002193 .privileges(redfish::privileges::getLogEntry)
2194 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002195 [&app](const crow::Request& req,
2196 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002197 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002198 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002199 {
2200 return;
2201 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002202 if (systemName != "system")
2203 {
2204 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2205 systemName);
2206 return;
2207 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002208 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002209
Ed Tanous002d39b2022-05-31 08:59:27 -07002210 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002211
Ed Tanous002d39b2022-05-31 08:59:27 -07002212 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2213 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002214
Ed Tanous002d39b2022-05-31 08:59:27 -07002215 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002216 if (ec == std::errc::invalid_argument ||
2217 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002218 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002219 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002220 return;
2221 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002222
Ed Tanous002d39b2022-05-31 08:59:27 -07002223 std::vector<std::filesystem::path> hostLoggerFiles;
2224 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2225 {
2226 BMCWEB_LOG_ERROR << "fail to get host log file path";
2227 return;
2228 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002229
Ed Tanous002d39b2022-05-31 08:59:27 -07002230 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002231 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002232 std::vector<std::string> logEntries;
2233 // We can get specific entry by skip and top. For example, if we
2234 // want to get nth entry, we can set skip = n-1 and top = 1 to
2235 // get that entry
2236 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2237 logCount))
2238 {
2239 messages::internalError(asyncResp->res);
2240 return;
2241 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002242
Ed Tanous002d39b2022-05-31 08:59:27 -07002243 if (!logEntries.empty())
2244 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002245 nlohmann::json::object_t hostLogEntry;
2246 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2247 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002248 return;
2249 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002250
Ed Tanous002d39b2022-05-31 08:59:27 -07002251 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002252 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002253 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002254}
2255
Claire Weinandd72e872022-08-15 14:20:06 -07002256inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002257 crow::App& app, const crow::Request& req,
2258 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2259{
2260 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2261 {
2262 return;
2263 }
2264 // Collections don't include the static data added by SubRoute
2265 // because it has a duplicate entry for members
2266 asyncResp->res.jsonValue["@odata.type"] =
2267 "#LogServiceCollection.LogServiceCollection";
2268 asyncResp->res.jsonValue["@odata.id"] =
2269 "/redfish/v1/Managers/bmc/LogServices";
2270 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2271 asyncResp->res.jsonValue["Description"] =
2272 "Collection of LogServices for this Manager";
2273 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2274 logServiceArray = nlohmann::json::array();
2275
2276#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002277 nlohmann::json::object_t journal;
2278 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2279 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002280#endif
2281
2282 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2283
2284#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
George Liu15912152023-01-11 10:18:18 +08002285 constexpr std::array<std::string_view, 1> interfaces = {
George Liu7a1dbc42022-12-07 16:03:22 +08002286 "xyz.openbmc_project.Collection.DeleteAll"};
2287 dbus::utility::getSubTreePaths(
2288 "/xyz/openbmc_project/dump", 0, interfaces,
Claire Weinanfdd26902022-03-01 14:18:25 -08002289 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +08002290 const boost::system::error_code& ec,
Claire Weinanfdd26902022-03-01 14:18:25 -08002291 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2292 if (ec)
2293 {
2294 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002295 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002296 << ec;
2297 // Assume that getting an error simply means there are no dump
2298 // LogServices. Return without adding any error response.
2299 return;
2300 }
2301
2302 nlohmann::json& logServiceArrayLocal =
2303 asyncResp->res.jsonValue["Members"];
2304
2305 for (const std::string& path : subTreePaths)
2306 {
2307 if (path == "/xyz/openbmc_project/dump/bmc")
2308 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002309 nlohmann::json::object_t member;
2310 member["@odata.id"] =
2311 "/redfish/v1/Managers/bmc/LogServices/Dump";
2312 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002313 }
2314 else if (path == "/xyz/openbmc_project/dump/faultlog")
2315 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002316 nlohmann::json::object_t member;
2317 member["@odata.id"] =
2318 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2319 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002320 }
2321 }
2322
2323 asyncResp->res.jsonValue["Members@odata.count"] =
2324 logServiceArrayLocal.size();
George Liu7a1dbc42022-12-07 16:03:22 +08002325 });
Claire Weinanfdd26902022-03-01 14:18:25 -08002326#endif
2327}
2328
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002329inline void requestRoutesBMCLogServiceCollection(App& app)
2330{
2331 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002332 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002333 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002334 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002335}
Ed Tanous1da66f72018-07-27 16:13:37 -07002336
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002337inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002338{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002339 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002340 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002341 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002342 [&app](const crow::Request& req,
2343 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002344 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002345 {
2346 return;
2347 }
2348 asyncResp->res.jsonValue["@odata.type"] =
2349 "#LogService.v1_1_0.LogService";
2350 asyncResp->res.jsonValue["@odata.id"] =
2351 "/redfish/v1/Managers/bmc/LogServices/Journal";
2352 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2353 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2354 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2355 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302356
Ed Tanous002d39b2022-05-31 08:59:27 -07002357 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002358 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2360 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2361 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302362
Ed Tanous002d39b2022-05-31 08:59:27 -07002363 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2364 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2365 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002366}
Jason M. Billse1f26342018-07-18 12:12:00 -07002367
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002368static int
2369 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2370 sd_journal* journal,
2371 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002372{
2373 // Get the Log Entry contents
2374 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002375
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002376 std::string message;
2377 std::string_view syslogID;
2378 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2379 if (ret < 0)
2380 {
2381 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2382 << strerror(-ret);
2383 }
2384 if (!syslogID.empty())
2385 {
2386 message += std::string(syslogID) + ": ";
2387 }
2388
Ed Tanous39e77502019-03-04 17:35:53 -08002389 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002390 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002391 if (ret < 0)
2392 {
2393 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2394 return 1;
2395 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002396 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002397
2398 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002399 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002400 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002401 if (ret < 0)
2402 {
2403 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002404 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002405
2406 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002407 std::string entryTimeStr;
2408 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002409 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002410 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002411 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002412
2413 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002414 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002415 bmcJournalLogEntryJson["@odata.id"] =
2416 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2417 bmcJournalLogEntryID;
2418 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2419 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2420 bmcJournalLogEntryJson["Message"] = std::move(message);
2421 bmcJournalLogEntryJson["EntryType"] = "Oem";
2422 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2423 : severity <= 4 ? "Warning"
2424 : "OK";
2425 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2426 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002427 return 0;
2428}
2429
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002430inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002431{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002432 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002433 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002434 .methods(boost::beast::http::verb::get)(
2435 [&app](const crow::Request& req,
2436 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2437 query_param::QueryCapabilities capabilities = {
2438 .canDelegateTop = true,
2439 .canDelegateSkip = true,
2440 };
2441 query_param::Query delegatedQuery;
2442 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002443 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002444 {
2445 return;
2446 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002447
2448 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002449 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002450
Ed Tanous002d39b2022-05-31 08:59:27 -07002451 // Collections don't include the static data added by SubRoute
2452 // because it has a duplicate entry for members
2453 asyncResp->res.jsonValue["@odata.type"] =
2454 "#LogEntryCollection.LogEntryCollection";
2455 asyncResp->res.jsonValue["@odata.id"] =
2456 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2457 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2458 asyncResp->res.jsonValue["Description"] =
2459 "Collection of BMC Journal Entries";
2460 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2461 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002462
Ed Tanous002d39b2022-05-31 08:59:27 -07002463 // Go through the journal and use the timestamp to create a
2464 // unique ID for each entry
2465 sd_journal* journalTmp = nullptr;
2466 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2467 if (ret < 0)
2468 {
2469 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2470 messages::internalError(asyncResp->res);
2471 return;
2472 }
2473 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2474 journalTmp, sd_journal_close);
2475 journalTmp = nullptr;
2476 uint64_t entryCount = 0;
2477 // Reset the unique ID on the first entry
2478 bool firstEntry = true;
2479 SD_JOURNAL_FOREACH(journal.get())
2480 {
2481 entryCount++;
2482 // Handle paging using skip (number of entries to skip from
2483 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002484 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002485 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002486 continue;
2487 }
2488
2489 std::string idStr;
2490 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2491 {
2492 continue;
2493 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002494 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002495
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002496 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002497 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2498 bmcJournalLogEntry) != 0)
2499 {
George Liu0fda0f12021-11-16 10:06:17 +08002500 messages::internalError(asyncResp->res);
2501 return;
2502 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002503 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002504 }
2505 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002506 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002507 {
2508 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2509 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002510 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002511 }
George Liu0fda0f12021-11-16 10:06:17 +08002512 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002513}
Jason M. Billse1f26342018-07-18 12:12:00 -07002514
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002515inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002516{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002517 BMCWEB_ROUTE(app,
2518 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002519 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002520 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002521 [&app](const crow::Request& req,
2522 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2523 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002524 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002525 {
2526 return;
2527 }
2528 // Convert the unique ID back to a timestamp to find the entry
2529 uint64_t ts = 0;
2530 uint64_t index = 0;
2531 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2532 {
2533 return;
2534 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002535
Ed Tanous002d39b2022-05-31 08:59:27 -07002536 sd_journal* journalTmp = nullptr;
2537 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2538 if (ret < 0)
2539 {
2540 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2541 messages::internalError(asyncResp->res);
2542 return;
2543 }
2544 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2545 journalTmp, sd_journal_close);
2546 journalTmp = nullptr;
2547 // Go to the timestamp in the log and move to the entry at the
2548 // index tracking the unique ID
2549 std::string idStr;
2550 bool firstEntry = true;
2551 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2552 if (ret < 0)
2553 {
2554 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2555 << strerror(-ret);
2556 messages::internalError(asyncResp->res);
2557 return;
2558 }
2559 for (uint64_t i = 0; i <= index; i++)
2560 {
2561 sd_journal_next(journal.get());
2562 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2563 {
2564 messages::internalError(asyncResp->res);
2565 return;
2566 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002567 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002568 }
2569 // Confirm that the entry ID matches what was requested
2570 if (idStr != entryID)
2571 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002572 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002573 return;
2574 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002575
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002576 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002577 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002578 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002579 {
2580 messages::internalError(asyncResp->res);
2581 return;
2582 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002583 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002584 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002585}
2586
Claire Weinanfdd26902022-03-01 14:18:25 -08002587inline void
2588 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2589 const std::string& dumpType)
2590{
2591 std::string dumpPath;
2592 std::string overWritePolicy;
2593 bool collectDiagnosticDataSupported = false;
2594
2595 if (dumpType == "BMC")
2596 {
2597 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2598 overWritePolicy = "WrapsWhenFull";
2599 collectDiagnosticDataSupported = true;
2600 }
2601 else if (dumpType == "FaultLog")
2602 {
2603 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2604 overWritePolicy = "Unknown";
2605 collectDiagnosticDataSupported = false;
2606 }
2607 else if (dumpType == "System")
2608 {
2609 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2610 overWritePolicy = "WrapsWhenFull";
2611 collectDiagnosticDataSupported = true;
2612 }
2613 else
2614 {
2615 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2616 << dumpType;
2617 messages::internalError(asyncResp->res);
2618 return;
2619 }
2620
2621 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2622 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2623 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2624 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2625 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2626 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2627
2628 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002629 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002630 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2631 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2632 redfishDateTimeOffset.second;
2633
2634 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2635 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2636 dumpPath + "/Actions/LogService.ClearLog";
2637
2638 if (collectDiagnosticDataSupported)
2639 {
2640 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2641 ["target"] =
2642 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2643 }
2644}
2645
2646inline void handleLogServicesDumpServiceGet(
2647 crow::App& app, const std::string& dumpType, const crow::Request& req,
2648 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2649{
2650 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2651 {
2652 return;
2653 }
2654 getDumpServiceInfo(asyncResp, dumpType);
2655}
2656
Ed Tanous22d268c2022-05-19 09:39:07 -07002657inline void handleLogServicesDumpServiceComputerSystemGet(
2658 crow::App& app, const crow::Request& req,
2659 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2660 const std::string& chassisId)
2661{
2662 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2663 {
2664 return;
2665 }
2666 if (chassisId != "system")
2667 {
2668 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2669 return;
2670 }
2671 getDumpServiceInfo(asyncResp, "System");
2672}
2673
Claire Weinanfdd26902022-03-01 14:18:25 -08002674inline void handleLogServicesDumpEntriesCollectionGet(
2675 crow::App& app, const std::string& dumpType, const crow::Request& req,
2676 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2677{
2678 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2679 {
2680 return;
2681 }
2682 getDumpEntryCollection(asyncResp, dumpType);
2683}
2684
Ed Tanous22d268c2022-05-19 09:39:07 -07002685inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2686 crow::App& app, const crow::Request& req,
2687 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2688 const std::string& chassisId)
2689{
2690 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2691 {
2692 return;
2693 }
2694 if (chassisId != "system")
2695 {
2696 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2697 return;
2698 }
2699 getDumpEntryCollection(asyncResp, "System");
2700}
2701
Claire Weinanfdd26902022-03-01 14:18:25 -08002702inline void handleLogServicesDumpEntryGet(
2703 crow::App& app, const std::string& dumpType, const crow::Request& req,
2704 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2705 const std::string& dumpId)
2706{
2707 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2708 {
2709 return;
2710 }
2711 getDumpEntryById(asyncResp, dumpId, dumpType);
2712}
Ed Tanous22d268c2022-05-19 09:39:07 -07002713inline void handleLogServicesDumpEntryComputerSystemGet(
2714 crow::App& app, const crow::Request& req,
2715 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2716 const std::string& chassisId, const std::string& dumpId)
2717{
2718 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2719 {
2720 return;
2721 }
2722 if (chassisId != "system")
2723 {
2724 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2725 return;
2726 }
2727 getDumpEntryById(asyncResp, dumpId, "System");
2728}
Claire Weinanfdd26902022-03-01 14:18:25 -08002729
2730inline void handleLogServicesDumpEntryDelete(
2731 crow::App& app, const std::string& dumpType, const crow::Request& req,
2732 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2733 const std::string& dumpId)
2734{
2735 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2736 {
2737 return;
2738 }
2739 deleteDumpEntry(asyncResp, dumpId, dumpType);
2740}
2741
Ed Tanous22d268c2022-05-19 09:39:07 -07002742inline void handleLogServicesDumpEntryComputerSystemDelete(
2743 crow::App& app, const crow::Request& req,
2744 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2745 const std::string& chassisId, const std::string& dumpId)
2746{
2747 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2748 {
2749 return;
2750 }
2751 if (chassisId != "system")
2752 {
2753 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2754 return;
2755 }
2756 deleteDumpEntry(asyncResp, dumpId, "System");
2757}
2758
Claire Weinanfdd26902022-03-01 14:18:25 -08002759inline void handleLogServicesDumpCollectDiagnosticDataPost(
2760 crow::App& app, const std::string& dumpType, const crow::Request& req,
2761 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2762{
2763 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2764 {
2765 return;
2766 }
2767 createDump(asyncResp, req, dumpType);
2768}
2769
Ed Tanous22d268c2022-05-19 09:39:07 -07002770inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2771 crow::App& app, const crow::Request& req,
2772 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2773 const std::string& chassisId)
2774{
2775 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2776 {
2777 return;
2778 }
2779 if (chassisId != "system")
2780 {
2781 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2782 return;
2783 }
2784 createDump(asyncResp, req, "System");
2785}
2786
Claire Weinanfdd26902022-03-01 14:18:25 -08002787inline void handleLogServicesDumpClearLogPost(
2788 crow::App& app, const std::string& dumpType, const crow::Request& req,
2789 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2790{
2791 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2792 {
2793 return;
2794 }
2795 clearDump(asyncResp, dumpType);
2796}
2797
Ed Tanous22d268c2022-05-19 09:39:07 -07002798inline void handleLogServicesDumpClearLogComputerSystemPost(
2799 crow::App& app, const crow::Request& req,
2800 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2801 const std::string& chassisId)
2802{
2803 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2804 {
2805 return;
2806 }
2807 if (chassisId != "system")
2808 {
2809 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2810 return;
2811 }
2812 clearDump(asyncResp, "System");
2813}
2814
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002815inline void requestRoutesBMCDumpService(App& app)
2816{
2817 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002818 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002819 .methods(boost::beast::http::verb::get)(std::bind_front(
2820 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002821}
2822
2823inline void requestRoutesBMCDumpEntryCollection(App& app)
2824{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002825 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002826 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002827 .methods(boost::beast::http::verb::get)(std::bind_front(
2828 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002829}
2830
2831inline void requestRoutesBMCDumpEntry(App& app)
2832{
2833 BMCWEB_ROUTE(app,
2834 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002835 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002836 .methods(boost::beast::http::verb::get)(std::bind_front(
2837 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2838
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002839 BMCWEB_ROUTE(app,
2840 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002841 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002842 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2843 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002844}
2845
2846inline void requestRoutesBMCDumpCreate(App& app)
2847{
George Liu0fda0f12021-11-16 10:06:17 +08002848 BMCWEB_ROUTE(
2849 app,
2850 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002851 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002852 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002853 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2854 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002855}
2856
2857inline void requestRoutesBMCDumpClear(App& app)
2858{
George Liu0fda0f12021-11-16 10:06:17 +08002859 BMCWEB_ROUTE(
2860 app,
2861 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002862 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002863 .methods(boost::beast::http::verb::post)(std::bind_front(
2864 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2865}
2866
2867inline void requestRoutesFaultLogDumpService(App& app)
2868{
2869 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2870 .privileges(redfish::privileges::getLogService)
2871 .methods(boost::beast::http::verb::get)(std::bind_front(
2872 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2873}
2874
2875inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2876{
2877 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2878 .privileges(redfish::privileges::getLogEntryCollection)
2879 .methods(boost::beast::http::verb::get)(
2880 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2881 std::ref(app), "FaultLog"));
2882}
2883
2884inline void requestRoutesFaultLogDumpEntry(App& app)
2885{
2886 BMCWEB_ROUTE(app,
2887 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2888 .privileges(redfish::privileges::getLogEntry)
2889 .methods(boost::beast::http::verb::get)(std::bind_front(
2890 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2891
2892 BMCWEB_ROUTE(app,
2893 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2894 .privileges(redfish::privileges::deleteLogEntry)
2895 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2896 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2897}
2898
2899inline void requestRoutesFaultLogDumpClear(App& app)
2900{
2901 BMCWEB_ROUTE(
2902 app,
2903 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2904 .privileges(redfish::privileges::postLogService)
2905 .methods(boost::beast::http::verb::post)(std::bind_front(
2906 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002907}
2908
2909inline void requestRoutesSystemDumpService(App& app)
2910{
Ed Tanous22d268c2022-05-19 09:39:07 -07002911 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002912 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002913 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002914 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002915}
2916
2917inline void requestRoutesSystemDumpEntryCollection(App& app)
2918{
Ed Tanous22d268c2022-05-19 09:39:07 -07002919 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002920 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002921 .methods(boost::beast::http::verb::get)(std::bind_front(
2922 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2923 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002924}
2925
2926inline void requestRoutesSystemDumpEntry(App& app)
2927{
2928 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002929 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002930 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002931 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002932 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002933
2934 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002935 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002936 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002937 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002938 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002939}
2940
2941inline void requestRoutesSystemDumpCreate(App& app)
2942{
George Liu0fda0f12021-11-16 10:06:17 +08002943 BMCWEB_ROUTE(
2944 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002945 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002946 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002947 .methods(boost::beast::http::verb::post)(std::bind_front(
2948 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2949 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002950}
2951
2952inline void requestRoutesSystemDumpClear(App& app)
2953{
George Liu0fda0f12021-11-16 10:06:17 +08002954 BMCWEB_ROUTE(
2955 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002956 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002957 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002958 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002959 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002960}
2961
2962inline void requestRoutesCrashdumpService(App& app)
2963{
2964 // Note: Deviated from redfish privilege registry for GET & HEAD
2965 // method for security reasons.
2966 /**
2967 * Functions triggers appropriate requests on DBus
2968 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002969 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002970 // This is incorrect, should be:
2971 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002972 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002973 .methods(boost::beast::http::verb::get)(
2974 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002975 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2976 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002977 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002978 {
2979 return;
2980 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002981 if (systemName != "system")
2982 {
2983 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2984 systemName);
2985 return;
2986 }
2987
Ed Tanous002d39b2022-05-31 08:59:27 -07002988 // Copy over the static data to include the entries added by
2989 // SubRoute
2990 asyncResp->res.jsonValue["@odata.id"] =
2991 "/redfish/v1/Systems/system/LogServices/Crashdump";
2992 asyncResp->res.jsonValue["@odata.type"] =
2993 "#LogService.v1_2_0.LogService";
2994 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2995 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2996 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2997 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2998 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302999
Ed Tanous002d39b2022-05-31 08:59:27 -07003000 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003001 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003002 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3003 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3004 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303005
Ed Tanous002d39b2022-05-31 08:59:27 -07003006 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3007 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3008 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
3009 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
3010 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
3011 ["target"] =
3012 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003013 });
3014}
3015
3016void inline requestRoutesCrashdumpClear(App& app)
3017{
George Liu0fda0f12021-11-16 10:06:17 +08003018 BMCWEB_ROUTE(
3019 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003020 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003021 // This is incorrect, should be:
3022 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003023 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003024 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003025 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003026 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3027 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003028 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003029 {
3030 return;
3031 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003032 if (systemName != "system")
3033 {
3034 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3035 systemName);
3036 return;
3037 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003038 crow::connections::systemBus->async_method_call(
3039 [asyncResp](const boost::system::error_code ec,
3040 const std::string&) {
3041 if (ec)
3042 {
3043 messages::internalError(asyncResp->res);
3044 return;
3045 }
3046 messages::success(asyncResp->res);
3047 },
3048 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
3049 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003050}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07003051
zhanghch058d1b46d2021-04-01 11:18:24 +08003052static void
3053 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3054 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07003055{
Johnathan Mantey043a0532020-03-10 17:15:28 -07003056 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08003057 [asyncResp, logID,
3058 &logEntryJson](const boost::system::error_code ec,
3059 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003060 if (ec)
3061 {
3062 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3063 if (ec.value() ==
3064 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08003065 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003066 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003067 }
3068 else
3069 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003070 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003071 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003072 return;
3073 }
3074
3075 std::string timestamp{};
3076 std::string filename{};
3077 std::string logfile{};
3078 parseCrashdumpParameters(params, filename, timestamp, logfile);
3079
3080 if (filename.empty() || timestamp.empty())
3081 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003082 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003083 return;
3084 }
3085
3086 std::string crashdumpURI =
3087 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
3088 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07003089 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003090 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003091 logEntry["@odata.id"] =
3092 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
3093 logEntry["Name"] = "CPU Crashdump";
3094 logEntry["Id"] = logID;
3095 logEntry["EntryType"] = "Oem";
3096 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
3097 logEntry["DiagnosticDataType"] = "OEM";
3098 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
3099 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07003100
3101 // If logEntryJson references an array of LogEntry resources
3102 // ('Members' list), then push this as a new entry, otherwise set it
3103 // directly
3104 if (logEntryJson.is_array())
3105 {
3106 logEntryJson.push_back(logEntry);
3107 asyncResp->res.jsonValue["Members@odata.count"] =
3108 logEntryJson.size();
3109 }
3110 else
3111 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07003112 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07003113 }
3114 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003115 sdbusplus::asio::getAllProperties(
3116 *crow::connections::systemBus, crashdumpObject,
3117 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3118 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07003119}
3120
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003121inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003122{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003123 // Note: Deviated from redfish privilege registry for GET & HEAD
3124 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003125 /**
3126 * Functions triggers appropriate requests on DBus
3127 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003128 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003129 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003130 // This is incorrect, should be.
3131 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07003132 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003133 .methods(boost::beast::http::verb::get)(
3134 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003135 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3136 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003137 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003138 {
3139 return;
3140 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003141 if (systemName != "system")
3142 {
3143 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3144 systemName);
3145 return;
3146 }
3147
George Liu7a1dbc42022-12-07 16:03:22 +08003148 constexpr std::array<std::string_view, 1> interfaces = {
3149 crashdumpInterface};
3150 dbus::utility::getSubTreePaths(
3151 "/", 0, interfaces,
3152 [asyncResp](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -07003153 const std::vector<std::string>& resp) {
3154 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003155 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003156 if (ec.value() !=
3157 boost::system::errc::no_such_file_or_directory)
3158 {
3159 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3160 << ec.message();
3161 messages::internalError(asyncResp->res);
3162 return;
3163 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003164 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003165 asyncResp->res.jsonValue["@odata.type"] =
3166 "#LogEntryCollection.LogEntryCollection";
3167 asyncResp->res.jsonValue["@odata.id"] =
3168 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3169 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3170 asyncResp->res.jsonValue["Description"] =
3171 "Collection of Crashdump Entries";
3172 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3173 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003174
Ed Tanous002d39b2022-05-31 08:59:27 -07003175 for (const std::string& path : resp)
3176 {
3177 const sdbusplus::message::object_path objPath(path);
3178 // Get the log ID
3179 std::string logID = objPath.filename();
3180 if (logID.empty())
3181 {
3182 continue;
3183 }
3184 // Add the log entry to the array
3185 logCrashdumpEntry(asyncResp, logID,
3186 asyncResp->res.jsonValue["Members"]);
3187 }
George Liu7a1dbc42022-12-07 16:03:22 +08003188 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003189 });
3190}
Ed Tanous1da66f72018-07-27 16:13:37 -07003191
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003192inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003193{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003194 // Note: Deviated from redfish privilege registry for GET & HEAD
3195 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003196
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003197 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003198 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003199 // this is incorrect, should be
3200 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003201 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003202 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003203 [&app](const crow::Request& req,
3204 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003205 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003206 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003207 {
3208 return;
3209 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003210 if (systemName != "system")
3211 {
3212 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3213 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003214 return;
3215 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003216 const std::string& logID = param;
3217 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3218 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003219}
Ed Tanous1da66f72018-07-27 16:13:37 -07003220
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003221inline void requestRoutesCrashdumpFile(App& app)
3222{
3223 // Note: Deviated from redfish privilege registry for GET & HEAD
3224 // method for security reasons.
3225 BMCWEB_ROUTE(
3226 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003227 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003228 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003229 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003230 [](const crow::Request& req,
3231 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003232 const std::string& systemName, const std::string& logID,
3233 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003234 // Do not call getRedfishRoute here since the crashdump file is not a
3235 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003236
3237 if (systemName != "system")
3238 {
3239 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3240 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003241 return;
3242 }
3243
Ed Tanous002d39b2022-05-31 08:59:27 -07003244 auto getStoredLogCallback =
3245 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3246 const boost::system::error_code ec,
3247 const std::vector<
3248 std::pair<std::string, dbus::utility::DbusVariantType>>&
3249 resp) {
3250 if (ec)
3251 {
3252 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3253 messages::internalError(asyncResp->res);
3254 return;
3255 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003256
Ed Tanous002d39b2022-05-31 08:59:27 -07003257 std::string dbusFilename{};
3258 std::string dbusTimestamp{};
3259 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003260
Ed Tanous002d39b2022-05-31 08:59:27 -07003261 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3262 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003263
Ed Tanous002d39b2022-05-31 08:59:27 -07003264 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3265 dbusFilepath.empty())
3266 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003267 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003268 return;
3269 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003270
Ed Tanous002d39b2022-05-31 08:59:27 -07003271 // Verify the file name parameter is correct
3272 if (fileName != dbusFilename)
3273 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003274 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003275 return;
3276 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003277
Ed Tanous002d39b2022-05-31 08:59:27 -07003278 if (!std::filesystem::exists(dbusFilepath))
3279 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003280 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003281 return;
3282 }
3283 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3284 asyncResp->res.body() =
3285 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003286
Ed Tanous002d39b2022-05-31 08:59:27 -07003287 // Configure this to be a file download when accessed
3288 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003289 asyncResp->res.addHeader(
3290 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003291 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003292 sdbusplus::asio::getAllProperties(
3293 *crow::connections::systemBus, crashdumpObject,
3294 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3295 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003296 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003297}
3298
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003299enum class OEMDiagnosticType
3300{
3301 onDemand,
3302 telemetry,
3303 invalid,
3304};
3305
Ed Tanousf7725d72022-03-07 12:46:00 -08003306inline OEMDiagnosticType
3307 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003308{
3309 if (oemDiagStr == "OnDemand")
3310 {
3311 return OEMDiagnosticType::onDemand;
3312 }
3313 if (oemDiagStr == "Telemetry")
3314 {
3315 return OEMDiagnosticType::telemetry;
3316 }
3317
3318 return OEMDiagnosticType::invalid;
3319}
3320
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003321inline void requestRoutesCrashdumpCollect(App& app)
3322{
3323 // Note: Deviated from redfish privilege registry for GET & HEAD
3324 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003325 BMCWEB_ROUTE(
3326 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003327 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003328 // The below is incorrect; Should be ConfigureManager
3329 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003330 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003331 .methods(boost::beast::http::verb::post)(
3332 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003333 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3334 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003335 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003336 {
3337 return;
3338 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003339
3340 if (systemName != "system")
3341 {
3342 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3343 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003344 return;
3345 }
3346
Ed Tanous002d39b2022-05-31 08:59:27 -07003347 std::string diagnosticDataType;
3348 std::string oemDiagnosticDataType;
3349 if (!redfish::json_util::readJsonAction(
3350 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3351 "OEMDiagnosticDataType", oemDiagnosticDataType))
3352 {
3353 return;
3354 }
3355
3356 if (diagnosticDataType != "OEM")
3357 {
3358 BMCWEB_LOG_ERROR
3359 << "Only OEM DiagnosticDataType supported for Crashdump";
3360 messages::actionParameterValueFormatError(
3361 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3362 "CollectDiagnosticData");
3363 return;
3364 }
3365
3366 OEMDiagnosticType oemDiagType =
3367 getOEMDiagnosticType(oemDiagnosticDataType);
3368
3369 std::string iface;
3370 std::string method;
3371 std::string taskMatchStr;
3372 if (oemDiagType == OEMDiagnosticType::onDemand)
3373 {
3374 iface = crashdumpOnDemandInterface;
3375 method = "GenerateOnDemandLog";
3376 taskMatchStr = "type='signal',"
3377 "interface='org.freedesktop.DBus.Properties',"
3378 "member='PropertiesChanged',"
3379 "arg0namespace='com.intel.crashdump'";
3380 }
3381 else if (oemDiagType == OEMDiagnosticType::telemetry)
3382 {
3383 iface = crashdumpTelemetryInterface;
3384 method = "GenerateTelemetryLog";
3385 taskMatchStr = "type='signal',"
3386 "interface='org.freedesktop.DBus.Properties',"
3387 "member='PropertiesChanged',"
3388 "arg0namespace='com.intel.crashdump'";
3389 }
3390 else
3391 {
3392 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3393 << oemDiagnosticDataType;
3394 messages::actionParameterValueFormatError(
3395 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3396 "CollectDiagnosticData");
3397 return;
3398 }
3399
3400 auto collectCrashdumpCallback =
3401 [asyncResp, payload(task::Payload(req)),
3402 taskMatchStr](const boost::system::error_code ec,
3403 const std::string&) mutable {
3404 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003405 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003406 if (ec.value() == boost::system::errc::operation_not_supported)
3407 {
3408 messages::resourceInStandby(asyncResp->res);
3409 }
3410 else if (ec.value() ==
3411 boost::system::errc::device_or_resource_busy)
3412 {
3413 messages::serviceTemporarilyUnavailable(asyncResp->res,
3414 "60");
3415 }
3416 else
3417 {
3418 messages::internalError(asyncResp->res);
3419 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003420 return;
3421 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003422 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003423 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003424 const std::shared_ptr<task::TaskData>& taskData) {
3425 if (!err)
3426 {
3427 taskData->messages.emplace_back(messages::taskCompletedOK(
3428 std::to_string(taskData->index)));
3429 taskData->state = "Completed";
3430 }
3431 return task::completed;
3432 },
3433 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003434
Ed Tanous002d39b2022-05-31 08:59:27 -07003435 task->startTimer(std::chrono::minutes(5));
3436 task->populateResp(asyncResp->res);
3437 task->payload.emplace(std::move(payload));
3438 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003439
Ed Tanous002d39b2022-05-31 08:59:27 -07003440 crow::connections::systemBus->async_method_call(
3441 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3442 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003443 });
3444}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003445
Andrew Geisslercb92c032018-08-17 07:56:14 -07003446/**
3447 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3448 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003449inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003450{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003451 /**
3452 * Function handles POST method request.
3453 * The Clear Log actions does not require any parameter.The action deletes
3454 * all entries found in the Entries collection for this Log Service.
3455 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003456
George Liu0fda0f12021-11-16 10:06:17 +08003457 BMCWEB_ROUTE(
3458 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003459 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003460 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003461 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003462 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003463 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3464 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003465 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003466 {
3467 return;
3468 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003469 if (systemName != "system")
3470 {
3471 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3472 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003473 return;
3474 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003475 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003476
Ed Tanous002d39b2022-05-31 08:59:27 -07003477 // Process response from Logging service.
3478 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3479 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3480 if (ec)
3481 {
3482 // TODO Handle for specific error code
3483 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3484 asyncResp->res.result(
3485 boost::beast::http::status::internal_server_error);
3486 return;
3487 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003488
Ed Tanous002d39b2022-05-31 08:59:27 -07003489 asyncResp->res.result(boost::beast::http::status::no_content);
3490 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003491
Ed Tanous002d39b2022-05-31 08:59:27 -07003492 // Make call to Logging service to request Clear Log
3493 crow::connections::systemBus->async_method_call(
3494 respHandler, "xyz.openbmc_project.Logging",
3495 "/xyz/openbmc_project/logging",
3496 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3497 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003498}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003499
3500/****************************************************
3501 * Redfish PostCode interfaces
3502 * using DBUS interface: getPostCodesTS
3503 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003504inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003505{
Ed Tanous22d268c2022-05-19 09:39:07 -07003506 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003507 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003508 .methods(boost::beast::http::verb::get)(
3509 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003510 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3511 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003512 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003513 {
3514 return;
3515 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003516 if (systemName != "system")
3517 {
3518 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3519 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003520 return;
3521 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003522 asyncResp->res.jsonValue["@odata.id"] =
3523 "/redfish/v1/Systems/system/LogServices/PostCodes";
3524 asyncResp->res.jsonValue["@odata.type"] =
3525 "#LogService.v1_1_0.LogService";
3526 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3527 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3528 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3529 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3530 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3531 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303532
Ed Tanous002d39b2022-05-31 08:59:27 -07003533 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003534 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003535 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3536 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3537 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303538
Ed Tanous002d39b2022-05-31 08:59:27 -07003539 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3540 {"target",
3541 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003542 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003543}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003544
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003545inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003546{
George Liu0fda0f12021-11-16 10:06:17 +08003547 BMCWEB_ROUTE(
3548 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003549 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003550 // The following privilege is incorrect; It should be ConfigureManager
3551 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003552 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003553 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003554 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003555 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3556 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003557 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003558 {
3559 return;
3560 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003561 if (systemName != "system")
3562 {
3563 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3564 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003565 return;
3566 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003567 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003568
Ed Tanous002d39b2022-05-31 08:59:27 -07003569 // Make call to post-code service to request clear all
3570 crow::connections::systemBus->async_method_call(
3571 [asyncResp](const boost::system::error_code ec) {
3572 if (ec)
3573 {
3574 // TODO Handle for specific error code
3575 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3576 << ec;
3577 asyncResp->res.result(
3578 boost::beast::http::status::internal_server_error);
3579 messages::internalError(asyncResp->res);
3580 return;
3581 }
3582 },
3583 "xyz.openbmc_project.State.Boot.PostCode0",
3584 "/xyz/openbmc_project/State/Boot/PostCode0",
3585 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3586 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003587}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003588
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003589/**
3590 * @brief Parse post code ID and get the current value and index value
3591 * eg: postCodeID=B1-2, currentValue=1, index=2
3592 *
3593 * @param[in] postCodeID Post Code ID
3594 * @param[out] currentValue Current value
3595 * @param[out] index Index value
3596 *
3597 * @return bool true if the parsing is successful, false the parsing fails
3598 */
3599inline static bool parsePostCode(const std::string& postCodeID,
3600 uint64_t& currentValue, uint16_t& index)
3601{
3602 std::vector<std::string> split;
3603 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3604 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3605 {
3606 return false;
3607 }
3608
3609 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3610 const char* start = split[0].data() + 1;
3611 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3612 const char* end = split[0].data() + split[0].size();
3613 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3614
3615 if (ptrIndex != end || ecIndex != std::errc())
3616 {
3617 return false;
3618 }
3619
3620 start = split[1].data();
3621
3622 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
3623 end = split[1].data() + split[1].size();
3624 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
3625
3626 return ptrValue == end && ecValue == std::errc();
3627}
3628
3629static bool fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003630 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303631 const boost::container::flat_map<
3632 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003633 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3634 const uint64_t skip = 0, const uint64_t top = 0)
3635{
3636 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003637 const registries::Message* message =
3638 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003639
3640 uint64_t currentCodeIndex = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003641 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303642 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3643 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003644 {
3645 currentCodeIndex++;
3646 std::string postcodeEntryID =
3647 "B" + std::to_string(bootIndex) + "-" +
3648 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3649
3650 uint64_t usecSinceEpoch = code.first;
3651 uint64_t usTimeOffset = 0;
3652
3653 if (1 == currentCodeIndex)
3654 { // already incremented
3655 firstCodeTimeUs = code.first;
3656 }
3657 else
3658 {
3659 usTimeOffset = code.first - firstCodeTimeUs;
3660 }
3661
3662 // skip if no specific codeIndex is specified and currentCodeIndex does
3663 // not fall between top and skip
3664 if ((codeIndex == 0) &&
3665 (currentCodeIndex <= skip || currentCodeIndex > top))
3666 {
3667 continue;
3668 }
3669
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003670 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003671 // currentIndex
3672 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3673 {
3674 // This is done for simplicity. 1st entry is needed to calculate
3675 // time offset. To improve efficiency, one can get to the entry
3676 // directly (possibly with flatmap's nth method)
3677 continue;
3678 }
3679
3680 // currentCodeIndex is within top and skip or equal to specified code
3681 // index
3682
3683 // Get the Created time from the timestamp
3684 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003685 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003686 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003687
3688 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3689 std::ostringstream hexCode;
3690 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303691 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003692 std::ostringstream timeOffsetStr;
3693 // Set Fixed -Point Notation
3694 timeOffsetStr << std::fixed;
3695 // Set precision to 4 digits
3696 timeOffsetStr << std::setprecision(4);
3697 // Add double to stream
3698 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3699 std::vector<std::string> messageArgs = {
3700 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3701
3702 // Get MessageArgs template from message registry
3703 std::string msg;
3704 if (message != nullptr)
3705 {
3706 msg = message->message;
3707
3708 // fill in this post code value
3709 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003710 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003711 {
3712 std::string argStr = "%" + std::to_string(++i);
3713 size_t argPos = msg.find(argStr);
3714 if (argPos != std::string::npos)
3715 {
3716 msg.replace(argPos, argStr.length(), messageArg);
3717 }
3718 }
3719 }
3720
Tim Leed4342a92020-04-27 11:47:58 +08003721 // Get Severity template from message registry
3722 std::string severity;
3723 if (message != nullptr)
3724 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003725 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003726 }
3727
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003728 // Format entry
3729 nlohmann::json::object_t bmcLogEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05003730 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003731 bmcLogEntry["@odata.id"] =
3732 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3733 postcodeEntryID;
3734 bmcLogEntry["Name"] = "POST Code Log Entry";
3735 bmcLogEntry["Id"] = postcodeEntryID;
3736 bmcLogEntry["Message"] = std::move(msg);
3737 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3738 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3739 bmcLogEntry["EntryType"] = "Event";
3740 bmcLogEntry["Severity"] = std::move(severity);
3741 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003742 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3743 {
3744 bmcLogEntry["AdditionalDataURI"] =
3745 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3746 postcodeEntryID + "/attachment";
3747 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003748
3749 // codeIndex is only specified when querying single entry, return only
3750 // that entry in this case
3751 if (codeIndex != 0)
3752 {
3753 aResp->res.jsonValue.update(bmcLogEntry);
3754 return true;
3755 }
3756
3757 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
3758 logEntryArray.push_back(std::move(bmcLogEntry));
ZhikuiRena3316fc2020-01-29 14:58:08 -08003759 }
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003760
3761 // Return value is always false when querying multiple entries
3762 return false;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003763}
3764
zhanghch058d1b46d2021-04-01 11:18:24 +08003765static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003766 const std::string& entryId)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003767{
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003768 uint16_t bootIndex = 0;
3769 uint64_t codeIndex = 0;
3770 if (!parsePostCode(entryId, codeIndex, bootIndex))
3771 {
3772 // Requested ID was not found
3773 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3774 return;
3775 }
3776
3777 if (bootIndex == 0 || codeIndex == 0)
3778 {
3779 // 0 is an invalid index
3780 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3781 return;
3782 }
3783
ZhikuiRena3316fc2020-01-29 14:58:08 -08003784 crow::connections::systemBus->async_method_call(
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003785 [aResp, entryId, bootIndex,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303786 codeIndex](const boost::system::error_code ec,
3787 const boost::container::flat_map<
3788 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3789 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003790 if (ec)
3791 {
3792 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3793 messages::internalError(aResp->res);
3794 return;
3795 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003796
Ed Tanous002d39b2022-05-31 08:59:27 -07003797 if (postcode.empty())
3798 {
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003799 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
Ed Tanous002d39b2022-05-31 08:59:27 -07003800 return;
3801 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003802
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08003803 if (!fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex))
3804 {
3805 messages::resourceNotFound(aResp->res, "LogEntry", entryId);
3806 return;
3807 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003808 },
Jonathan Doman15124762021-01-07 17:54:17 -08003809 "xyz.openbmc_project.State.Boot.PostCode0",
3810 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003811 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3812 bootIndex);
3813}
3814
zhanghch058d1b46d2021-04-01 11:18:24 +08003815static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003816 const uint16_t bootIndex,
3817 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003818 const uint64_t entryCount, size_t skip,
3819 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003820{
3821 crow::connections::systemBus->async_method_call(
3822 [aResp, bootIndex, bootCount, entryCount, skip,
3823 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303824 const boost::container::flat_map<
3825 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3826 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003827 if (ec)
3828 {
3829 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3830 messages::internalError(aResp->res);
3831 return;
3832 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003833
Ed Tanous002d39b2022-05-31 08:59:27 -07003834 uint64_t endCount = entryCount;
3835 if (!postcode.empty())
3836 {
3837 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003838 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003839 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003840 uint64_t thisBootSkip =
3841 std::max(static_cast<uint64_t>(skip), entryCount) -
3842 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003843 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003844 std::min(static_cast<uint64_t>(top + skip), endCount) -
3845 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003846
3847 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3848 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003849 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003850 aResp->res.jsonValue["Members@odata.count"] = endCount;
3851 }
3852
3853 // continue to previous bootIndex
3854 if (bootIndex < bootCount)
3855 {
3856 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3857 bootCount, endCount, skip, top);
3858 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003859 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003860 {
3861 aResp->res.jsonValue["Members@odata.nextLink"] =
3862 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3863 std::to_string(skip + top);
3864 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003865 },
Jonathan Doman15124762021-01-07 17:54:17 -08003866 "xyz.openbmc_project.State.Boot.PostCode0",
3867 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003868 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3869 bootIndex);
3870}
3871
zhanghch058d1b46d2021-04-01 11:18:24 +08003872static void
3873 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003874 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003875{
3876 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003877 sdbusplus::asio::getProperty<uint16_t>(
3878 *crow::connections::systemBus,
3879 "xyz.openbmc_project.State.Boot.PostCode0",
3880 "/xyz/openbmc_project/State/Boot/PostCode0",
3881 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3882 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3883 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003884 if (ec)
3885 {
3886 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3887 messages::internalError(aResp->res);
3888 return;
3889 }
3890 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003891 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003892}
3893
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003894inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003895{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003896 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003897 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003898 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003899 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003900 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003901 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3902 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003903 query_param::QueryCapabilities capabilities = {
3904 .canDelegateTop = true,
3905 .canDelegateSkip = true,
3906 };
3907 query_param::Query delegatedQuery;
3908 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003909 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003910 {
3911 return;
3912 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003913
3914 if (systemName != "system")
3915 {
3916 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3917 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003918 return;
3919 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003920 asyncResp->res.jsonValue["@odata.type"] =
3921 "#LogEntryCollection.LogEntryCollection";
3922 asyncResp->res.jsonValue["@odata.id"] =
3923 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3924 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3925 asyncResp->res.jsonValue["Description"] =
3926 "Collection of POST Code Log Entries";
3927 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3928 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003929 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003930 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003931 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003932 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003933}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003934
George Liu647b3cd2021-07-05 12:43:56 +08003935inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3936{
George Liu0fda0f12021-11-16 10:06:17 +08003937 BMCWEB_ROUTE(
3938 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003939 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003940 .privileges(redfish::privileges::getLogEntry)
3941 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003942 [&app](const crow::Request& req,
3943 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003944 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003945 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003946 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003947 {
3948 return;
3949 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003950 if (http_helpers::isContentTypeAllowed(
3951 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003952 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003953 {
3954 asyncResp->res.result(boost::beast::http::status::bad_request);
3955 return;
3956 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003957 if (systemName != "system")
3958 {
3959 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3960 systemName);
Ed Tanous22d268c2022-05-19 09:39:07 -07003961 return;
3962 }
George Liu647b3cd2021-07-05 12:43:56 +08003963
Ed Tanous002d39b2022-05-31 08:59:27 -07003964 uint64_t currentValue = 0;
3965 uint16_t index = 0;
3966 if (!parsePostCode(postCodeID, currentValue, index))
3967 {
3968 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3969 return;
3970 }
George Liu647b3cd2021-07-05 12:43:56 +08003971
Ed Tanous002d39b2022-05-31 08:59:27 -07003972 crow::connections::systemBus->async_method_call(
3973 [asyncResp, postCodeID, currentValue](
3974 const boost::system::error_code ec,
3975 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3976 postcodes) {
3977 if (ec.value() == EBADR)
3978 {
3979 messages::resourceNotFound(asyncResp->res, "LogEntry",
3980 postCodeID);
3981 return;
3982 }
3983 if (ec)
3984 {
3985 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3986 messages::internalError(asyncResp->res);
3987 return;
3988 }
George Liu647b3cd2021-07-05 12:43:56 +08003989
Ed Tanous002d39b2022-05-31 08:59:27 -07003990 size_t value = static_cast<size_t>(currentValue) - 1;
3991 if (value == std::string::npos || postcodes.size() < currentValue)
3992 {
3993 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3994 messages::resourceNotFound(asyncResp->res, "LogEntry",
3995 postCodeID);
3996 return;
3997 }
George Liu647b3cd2021-07-05 12:43:56 +08003998
Ed Tanous002d39b2022-05-31 08:59:27 -07003999 const auto& [tID, c] = postcodes[value];
4000 if (c.empty())
4001 {
4002 BMCWEB_LOG_INFO << "No found post code data";
4003 messages::resourceNotFound(asyncResp->res, "LogEntry",
4004 postCodeID);
4005 return;
4006 }
4007 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
4008 const char* d = reinterpret_cast<const char*>(c.data());
4009 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08004010
Ed Tanousd9f6c622022-03-17 09:12:17 -07004011 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07004012 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07004013 asyncResp->res.addHeader(
4014 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07004015 asyncResp->res.body() = crow::utility::base64encode(strData);
4016 },
4017 "xyz.openbmc_project.State.Boot.PostCode0",
4018 "/xyz/openbmc_project/State/Boot/PostCode0",
4019 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
4020 });
George Liu647b3cd2021-07-05 12:43:56 +08004021}
4022
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004023inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08004024{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004025 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07004026 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07004027 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004028 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07004029 [&app](const crow::Request& req,
4030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07004031 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00004032 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07004033 {
4034 return;
4035 }
Ed Tanous22d268c2022-05-19 09:39:07 -07004036 if (systemName != "system")
4037 {
4038 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
4039 systemName);
4040 return;
4041 }
4042
Jiaqing Zhao6f284d22022-10-10 15:56:45 +08004043 getPostCodeForEntry(asyncResp, targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07004044 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07004045}
ZhikuiRena3316fc2020-01-29 14:58:08 -08004046
Ed Tanous1da66f72018-07-27 16:13:37 -07004047} // namespace redfish