blob: ec873b1ac7b36222bf5cea00289321c5c4296a8c [file] [log] [blame]
Ed Tanous1da66f72018-07-27 16:13:37 -07001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
Spencer Kub7028eb2021-10-26 15:27:35 +080018#include "gzfile.hpp"
George Liu647b3cd2021-07-05 12:43:56 +080019#include "http_utility.hpp"
Spencer Kub7028eb2021-10-26 15:27:35 +080020#include "human_sort.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070021#include "registries.hpp"
22#include "registries/base_message_registry.hpp"
23#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080024#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070025
Jason M. Billse1f26342018-07-18 12:12:00 -070026#include <systemd/sd-journal.h>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060027#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070028
John Edward Broadbent7e860f12021-04-08 15:57:16 -070029#include <app.hpp>
Ed Tanous9896eae2022-07-23 15:07:33 -070030#include <boost/algorithm/string/case_conv.hpp>
Ed Tanous11ba3972022-07-11 09:50:41 -070031#include <boost/algorithm/string/classification.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060032#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070033#include <boost/algorithm/string/split.hpp>
Ed Tanous07c8c202022-07-11 10:08:08 -070034#include <boost/beast/http/verb.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070035#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080036#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080037#include <dbus_utility.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070038#include <error_messages.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070039#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070040#include <registries/privilege_registry.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020041#include <sdbusplus/asio/property.hpp>
42#include <sdbusplus/unpack_properties.hpp>
43#include <utils/dbus_utils.hpp>
Ed Tanous2b829372022-08-03 14:22:34 -070044#include <utils/time_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045
George Liu647b3cd2021-07-05 12:43:56 +080046#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070047#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080048#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070049#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070050#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080051#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070052
53namespace redfish
54{
55
Gunnar Mills1214b7e2020-06-04 10:11:30 -050056constexpr char const* crashdumpObject = "com.intel.crashdump";
57constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050058constexpr char const* crashdumpInterface = "com.intel.crashdump";
59constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070060 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050061constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070062 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070063constexpr char const* crashdumpTelemetryInterface =
64 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070065
Ed Tanousfffb8c12022-02-07 23:53:03 -080066namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070067{
Ed Tanous26702d02021-11-03 15:02:33 -070068static const Message*
69 getMessageFromRegistry(const std::string& messageKey,
70 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070071{
Ed Tanous002d39b2022-05-31 08:59:27 -070072 std::span<const MessageEntry>::iterator messageIt =
73 std::find_if(registry.begin(), registry.end(),
74 [&messageKey](const MessageEntry& messageEntry) {
75 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070076 });
77 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070078 {
79 return &messageIt->second;
80 }
81
82 return nullptr;
83}
84
Gunnar Mills1214b7e2020-06-04 10:11:30 -050085static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070086{
87 // Redfish MessageIds are in the form
88 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
89 // the right Message
90 std::vector<std::string> fields;
91 fields.reserve(4);
92 boost::split(fields, messageID, boost::is_any_of("."));
Ed Tanous02cad962022-06-30 16:50:15 -070093 const std::string& registryName = fields[0];
94 const std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070095
96 // Find the right registry and check it for the MessageKey
97 if (std::string(base::header.registryPrefix) == registryName)
98 {
99 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700100 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700101 }
102 if (std::string(openbmc::header.registryPrefix) == registryName)
103 {
104 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -0700105 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700106 }
107 return nullptr;
108}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800109} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700110
James Feistf6150402019-01-08 10:36:20 -0800111namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700112
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500113inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700114{
Ed Tanousd4d25792020-09-29 15:15:03 -0700115 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
116 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
117 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
118 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700119 {
120 return "Critical";
121 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700122 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
123 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
124 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700125 {
126 return "OK";
127 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700128 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700129 {
130 return "Warning";
131 }
132 return "";
133}
134
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700135inline static int getJournalMetadata(sd_journal* journal,
136 const std::string_view& field,
137 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700138{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500139 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700140 size_t length = 0;
141 int ret = 0;
142 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800143 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
144 const void** dataVoid = reinterpret_cast<const void**>(&data);
145
146 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700147 if (ret < 0)
148 {
149 return ret;
150 }
Ed Tanous39e77502019-03-04 17:35:53 -0800151 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700152 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000153 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700154 return ret;
155}
156
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700157inline static int getJournalMetadata(sd_journal* journal,
158 const std::string_view& field,
159 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700160{
161 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800162 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700163 // Get the metadata from the requested field of the journal entry
164 ret = getJournalMetadata(journal, field, metadata);
165 if (ret < 0)
166 {
167 return ret;
168 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000169 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700170 return ret;
171}
172
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700173inline static bool getEntryTimestamp(sd_journal* journal,
174 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800175{
176 int ret = 0;
177 uint64_t timestamp = 0;
178 ret = sd_journal_get_realtime_usec(journal, &timestamp);
179 if (ret < 0)
180 {
181 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
182 << strerror(-ret);
183 return false;
184 }
Ed Tanous2b829372022-08-03 14:22:34 -0700185 entryTimestamp =
186 redfish::time_utils::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500187 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800188}
Ed Tanous50b8a432022-02-03 16:29:50 -0800189
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700190inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
191 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700192{
193 int ret = 0;
194 static uint64_t prevTs = 0;
195 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700196 if (firstEntry)
197 {
198 prevTs = 0;
199 }
200
Jason M. Bills16428a12018-11-02 12:42:29 -0700201 // Get the entry timestamp
202 uint64_t curTs = 0;
203 ret = sd_journal_get_realtime_usec(journal, &curTs);
204 if (ret < 0)
205 {
206 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
207 << strerror(-ret);
208 return false;
209 }
210 // If the timestamp isn't unique, increment the index
211 if (curTs == prevTs)
212 {
213 index++;
214 }
215 else
216 {
217 // Otherwise, reset it
218 index = 0;
219 }
220 // Save the timestamp
221 prevTs = curTs;
222
223 entryID = std::to_string(curTs);
224 if (index > 0)
225 {
226 entryID += "_" + std::to_string(index);
227 }
228 return true;
229}
230
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500231static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700232 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700233{
Ed Tanous271584a2019-07-09 16:24:22 -0700234 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700235 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700236 if (firstEntry)
237 {
238 prevTs = 0;
239 }
240
Jason M. Bills95820182019-04-22 16:25:34 -0700241 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700242 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700243 std::tm timeStruct = {};
244 std::istringstream entryStream(logEntry);
245 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
246 {
247 curTs = std::mktime(&timeStruct);
248 }
249 // If the timestamp isn't unique, increment the index
250 if (curTs == prevTs)
251 {
252 index++;
253 }
254 else
255 {
256 // Otherwise, reset it
257 index = 0;
258 }
259 // Save the timestamp
260 prevTs = curTs;
261
262 entryID = std::to_string(curTs);
263 if (index > 0)
264 {
265 entryID += "_" + std::to_string(index);
266 }
267 return true;
268}
269
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700270inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800271 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
272 const std::string& entryID, uint64_t& timestamp,
273 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700274{
275 if (entryID.empty())
276 {
277 return false;
278 }
279 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800280 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700281
Ed Tanous81ce6092020-12-17 16:54:55 +0000282 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800283 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700284 {
285 // Timestamp has an index
286 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800287 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700288 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700289 auto [ptr, ec] = std::from_chars(
290 indexStr.data(), indexStr.data() + indexStr.size(), index);
291 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700292 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800293 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700294 return false;
295 }
296 }
297 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700298 auto [ptr, ec] =
299 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
300 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700301 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +0800302 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700303 return false;
304 }
305 return true;
306}
307
Jason M. Bills95820182019-04-22 16:25:34 -0700308static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500309 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700310{
311 static const std::filesystem::path redfishLogDir = "/var/log";
312 static const std::string redfishLogFilename = "redfish";
313
314 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500315 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700316 std::filesystem::directory_iterator(redfishLogDir))
317 {
318 // If we find a redfish log file, save the path
319 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700320 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700321 {
322 redfishLogFiles.emplace_back(redfishLogDir / filename);
323 }
324 }
325 // As the log files rotate, they are appended with a ".#" that is higher for
326 // the older logs. Since we don't expect more than 10 log files, we
327 // can just sort the list to get them in order from newest to oldest
328 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
329
330 return !redfishLogFiles.empty();
331}
332
Claire Weinanaefe3782022-07-15 19:17:19 -0700333inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800334 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700335 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700336 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
337{
338 for (const auto& interfaceMap : object.second)
339 {
340 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
341 {
342 for (const auto& propertyMap : interfaceMap.second)
343 {
344 if (propertyMap.first == "Status")
345 {
346 const auto* status =
347 std::get_if<std::string>(&propertyMap.second);
348 if (status == nullptr)
349 {
350 messages::internalError(asyncResp->res);
351 break;
352 }
353 dumpStatus = *status;
354 }
355 }
356 }
357 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
358 {
359 for (const auto& propertyMap : interfaceMap.second)
360 {
361 if (propertyMap.first == "Size")
362 {
363 const auto* sizePtr =
364 std::get_if<uint64_t>(&propertyMap.second);
365 if (sizePtr == nullptr)
366 {
367 messages::internalError(asyncResp->res);
368 break;
369 }
370 size = *sizePtr;
371 break;
372 }
373 }
374 }
375 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
376 {
377 for (const auto& propertyMap : interfaceMap.second)
378 {
379 if (propertyMap.first == "Elapsed")
380 {
381 const uint64_t* usecsTimeStamp =
382 std::get_if<uint64_t>(&propertyMap.second);
383 if (usecsTimeStamp == nullptr)
384 {
385 messages::internalError(asyncResp->res);
386 break;
387 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700388 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700389 break;
390 }
391 }
392 }
393 }
394}
395
Nan Zhou21ab4042022-06-26 23:07:40 +0000396static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800397{
398 std::string entriesPath;
399
400 if (dumpType == "BMC")
401 {
402 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
403 }
404 else if (dumpType == "FaultLog")
405 {
406 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
407 }
408 else if (dumpType == "System")
409 {
410 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
411 }
412 else
413 {
414 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
415 << dumpType;
416 }
417
418 // Returns empty string on error
419 return entriesPath;
420}
421
zhanghch058d1b46d2021-04-01 11:18:24 +0800422inline void
423 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
424 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500425{
Claire Weinanfdd26902022-03-01 14:18:25 -0800426 std::string entriesPath = getDumpEntriesPath(dumpType);
427 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500428 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500429 messages::internalError(asyncResp->res);
430 return;
431 }
432
433 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800434 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800435 dumpType](const boost::system::error_code ec,
436 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 if (ec)
438 {
439 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
440 messages::internalError(asyncResp->res);
441 return;
442 }
443
Claire Weinanfdd26902022-03-01 14:18:25 -0800444 // Remove ending slash
445 std::string odataIdStr = entriesPath;
446 if (!odataIdStr.empty())
447 {
448 odataIdStr.pop_back();
449 }
450
451 asyncResp->res.jsonValue["@odata.type"] =
452 "#LogEntryCollection.LogEntryCollection";
453 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
454 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
455 asyncResp->res.jsonValue["Description"] =
456 "Collection of " + dumpType + " Dump Entries";
457
Ed Tanous002d39b2022-05-31 08:59:27 -0700458 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
459 entriesArray = nlohmann::json::array();
460 std::string dumpEntryPath =
461 "/xyz/openbmc_project/dump/" +
462 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
463
464 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
465 return AlphanumLess<std::string>()(l.first.filename(),
466 r.first.filename());
467 });
468
469 for (auto& object : resp)
470 {
471 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500472 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700473 continue;
474 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700475 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700476 uint64_t size = 0;
477 std::string dumpStatus;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700478 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700479
480 std::string entryID = object.first.filename();
481 if (entryID.empty())
482 {
483 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500484 }
485
Claire Weinanc6fecda2022-07-15 10:43:25 -0700486 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700487 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700488
489 if (dumpStatus !=
490 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
491 !dumpStatus.empty())
492 {
493 // Dump status is not Complete, no need to enumerate
494 continue;
495 }
496
Vijay Lobo9c11a172021-10-07 16:53:16 -0500497 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800498 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 thisEntry["Id"] = entryID;
500 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 thisEntry["Name"] = dumpType + " Dump Entry";
502
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 if (dumpType == "BMC")
504 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700505 thisEntry["Created"] = redfish::time_utils::getDateTimeUint(
506 timestampUs / 1000 / 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 thisEntry["DiagnosticDataType"] = "Manager";
508 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800509 entriesPath + entryID + "/attachment";
510 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700512 else if (dumpType == "FaultLog")
513 {
514 thisEntry["Created"] =
515 redfish::time_utils::getDateTimeUintUs(timestampUs);
516 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 else if (dumpType == "System")
518 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700519 thisEntry["Created"] = redfish::time_utils::getDateTimeUint(
520 timestampUs / 1000 / 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700521 thisEntry["DiagnosticDataType"] = "OEM";
522 thisEntry["OEMDiagnosticDataType"] = "System";
523 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800524 entriesPath + entryID + "/attachment";
525 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700526 }
527 entriesArray.push_back(std::move(thisEntry));
528 }
529 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500530 },
531 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
532 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
533}
534
zhanghch058d1b46d2021-04-01 11:18:24 +0800535inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700536 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800537 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500538{
Claire Weinanfdd26902022-03-01 14:18:25 -0800539 std::string entriesPath = getDumpEntriesPath(dumpType);
540 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500541 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500542 messages::internalError(asyncResp->res);
543 return;
544 }
545
546 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800547 [asyncResp, entryID, dumpType,
548 entriesPath](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700549 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700550 if (ec)
551 {
552 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
553 messages::internalError(asyncResp->res);
554 return;
555 }
556
557 bool foundDumpEntry = false;
558 std::string dumpEntryPath =
559 "/xyz/openbmc_project/dump/" +
560 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
561
562 for (const auto& objectPath : resp)
563 {
564 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500565 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700566 continue;
567 }
568
569 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700570 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 uint64_t size = 0;
572 std::string dumpStatus;
573
Claire Weinanaefe3782022-07-15 19:17:19 -0700574 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700575 timestampUs, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700576
577 if (dumpStatus !=
578 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
579 !dumpStatus.empty())
580 {
581 // Dump status is not Complete
582 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200583 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
584 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500585 return;
586 }
587
Ed Tanous002d39b2022-05-31 08:59:27 -0700588 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -0500589 "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800590 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700591 asyncResp->res.jsonValue["Id"] = entryID;
592 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700593 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500594
Ed Tanous002d39b2022-05-31 08:59:27 -0700595 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500596 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700597 asyncResp->res.jsonValue["Created"] =
598 redfish::time_utils::getDateTimeUint(timestampUs / 1000 /
599 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700600 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
601 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800602 entriesPath + entryID + "/attachment";
603 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500604 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700605 else if (dumpType == "FaultLog")
606 {
607 asyncResp->res.jsonValue["Created"] =
608 redfish::time_utils::getDateTimeUintUs(timestampUs);
609 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700610 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500611 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700612 asyncResp->res.jsonValue["Created"] =
613 redfish::time_utils::getDateTimeUint(timestampUs / 1000 /
614 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700615 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
616 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
617 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800618 entriesPath + entryID + "/attachment";
619 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500620 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700621 }
622 if (!foundDumpEntry)
623 {
624 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
625 messages::internalError(asyncResp->res);
626 return;
627 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500628 },
629 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
630 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
631}
632
zhanghch058d1b46d2021-04-01 11:18:24 +0800633inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800634 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500635 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500636{
Ed Tanous002d39b2022-05-31 08:59:27 -0700637 auto respHandler =
638 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
640 if (ec)
641 {
George Liu3de8d8b2021-03-22 17:49:39 +0800642 if (ec.value() == EBADR)
643 {
644 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
645 return;
646 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500647 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800648 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500649 messages::internalError(asyncResp->res);
650 return;
651 }
652 };
653 crow::connections::systemBus->async_method_call(
654 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500655 "/xyz/openbmc_project/dump/" +
656 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
657 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500658 "xyz.openbmc_project.Object.Delete", "Delete");
659}
660
zhanghch058d1b46d2021-04-01 11:18:24 +0800661inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700662 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800663 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
664 const uint32_t& dumpId, const std::string& dumpPath,
665 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500666{
667 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -0500668 [dumpId, dumpPath,
669 dumpType](boost::system::error_code err, sdbusplus::message_t& m,
670 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700671 if (err)
672 {
673 BMCWEB_LOG_ERROR << "Error in creating a dump";
674 taskData->state = "Cancelled";
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500675 return task::completed;
Ed Tanous002d39b2022-05-31 08:59:27 -0700676 }
677
678 dbus::utility::DBusInteracesMap interfacesList;
679
680 sdbusplus::message::object_path objPath;
681
682 m.read(objPath, interfacesList);
683
684 if (objPath.str ==
685 "/xyz/openbmc_project/dump/" +
686 std::string(boost::algorithm::to_lower_copy(dumpType)) +
687 "/entry/" + std::to_string(dumpId))
688 {
689 nlohmann::json retMessage = messages::success();
690 taskData->messages.emplace_back(retMessage);
691
692 std::string headerLoc =
693 "Location: " + dumpPath + std::to_string(dumpId);
694 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
695
696 taskData->state = "Completed";
697 return task::completed;
698 }
699 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500700 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800701 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500702 "member='InterfacesAdded', "
703 "path='/xyz/openbmc_project/dump'");
704
705 task->startTimer(std::chrono::minutes(3));
706 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700707 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500708}
709
zhanghch058d1b46d2021-04-01 11:18:24 +0800710inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
711 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500712{
Claire Weinanfdd26902022-03-01 14:18:25 -0800713 std::string dumpPath = getDumpEntriesPath(dumpType);
714 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500715 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500716 messages::internalError(asyncResp->res);
717 return;
718 }
719
720 std::optional<std::string> diagnosticDataType;
721 std::optional<std::string> oemDiagnosticDataType;
722
Willy Tu15ed6782021-12-14 11:03:16 -0800723 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500724 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
725 "OEMDiagnosticDataType", oemDiagnosticDataType))
726 {
727 return;
728 }
729
730 if (dumpType == "System")
731 {
732 if (!oemDiagnosticDataType || !diagnosticDataType)
733 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800734 BMCWEB_LOG_ERROR
735 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500736 messages::actionParameterMissing(
737 asyncResp->res, "CollectDiagnosticData",
738 "DiagnosticDataType & OEMDiagnosticDataType");
739 return;
740 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700741 if ((*oemDiagnosticDataType != "System") ||
742 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500743 {
744 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700745 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500746 return;
747 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500748 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500749 }
750 else if (dumpType == "BMC")
751 {
752 if (!diagnosticDataType)
753 {
George Liu0fda0f12021-11-16 10:06:17 +0800754 BMCWEB_LOG_ERROR
755 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500756 messages::actionParameterMissing(
757 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
758 return;
759 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700760 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500761 {
762 BMCWEB_LOG_ERROR
763 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700764 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500765 return;
766 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500767 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
768 }
769 else
770 {
771 BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type";
772 messages::internalError(asyncResp->res);
773 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500774 }
775
776 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700777 [asyncResp, payload(task::Payload(req)), dumpPath,
778 dumpType](const boost::system::error_code ec,
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500779 const sdbusplus::message::message& msg,
Ed Tanous98be3e32021-09-16 15:05:36 -0700780 const uint32_t& dumpId) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700781 if (ec)
782 {
783 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500784 const sd_bus_error* dbusError = msg.get_error();
785 if (dbusError == nullptr)
786 {
787 messages::internalError(asyncResp->res);
788 return;
789 }
790
791 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
792 << " and error msg: " << dbusError->message;
793 if (std::string_view(
794 "xyz.openbmc_project.Common.Error.NotAllowed") ==
795 dbusError->name)
796 {
797 messages::resourceInStandby(asyncResp->res);
798 return;
799 }
800 if (std::string_view(
801 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
802 dbusError->name)
803 {
804 messages::serviceDisabled(asyncResp->res, dumpPath);
805 return;
806 }
807 if (std::string_view(
808 "xyz.openbmc_project.Common.Error.Unavailable") ==
809 dbusError->name)
810 {
811 messages::resourceInUse(asyncResp->res);
812 return;
813 }
814 // Other Dbus errors such as:
815 // xyz.openbmc_project.Common.Error.InvalidArgument &
816 // org.freedesktop.DBus.Error.InvalidArgs are all related to
817 // the dbus call that is made here in the bmcweb
818 // implementation and has nothing to do with the client's
819 // input in the request. Hence, returning internal error
820 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700821 messages::internalError(asyncResp->res);
822 return;
823 }
824 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500825
Ed Tanous002d39b2022-05-31 08:59:27 -0700826 createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
827 dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500828 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500829 "xyz.openbmc_project.Dump.Manager",
830 "/xyz/openbmc_project/dump/" +
831 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500832 "xyz.openbmc_project.Dump.Create", "CreateDump");
833}
834
zhanghch058d1b46d2021-04-01 11:18:24 +0800835inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
836 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500837{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500838 std::string dumpTypeLowerCopy =
839 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800840
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500841 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800842 [asyncResp, dumpType](
843 const boost::system::error_code ec,
844 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700845 if (ec)
846 {
847 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
848 messages::internalError(asyncResp->res);
849 return;
850 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500851
Ed Tanous002d39b2022-05-31 08:59:27 -0700852 for (const std::string& path : subTreePaths)
853 {
854 sdbusplus::message::object_path objPath(path);
855 std::string logID = objPath.filename();
856 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500857 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700858 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500859 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700860 deleteDumpEntry(asyncResp, logID, dumpType);
861 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500862 },
863 "xyz.openbmc_project.ObjectMapper",
864 "/xyz/openbmc_project/object_mapper",
865 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500866 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
867 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
868 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500869}
870
Ed Tanousb9d36b42022-02-26 21:42:46 -0800871inline static void
872 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
873 std::string& filename, std::string& timestamp,
874 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700875{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200876 const std::string* filenamePtr = nullptr;
877 const std::string* timestampPtr = nullptr;
878 const std::string* logfilePtr = nullptr;
879
880 const bool success = sdbusplus::unpackPropertiesNoThrow(
881 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
882 "Filename", filenamePtr, "Log", logfilePtr);
883
884 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700885 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200886 return;
887 }
888
889 if (filenamePtr != nullptr)
890 {
891 filename = *filenamePtr;
892 }
893
894 if (timestampPtr != nullptr)
895 {
896 timestamp = *timestampPtr;
897 }
898
899 if (logfilePtr != nullptr)
900 {
901 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -0700902 }
903}
904
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500905constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700906inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700907{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800908 /**
909 * Functions triggers appropriate requests on DBus
910 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700911 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700912 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700913 .methods(boost::beast::http::verb::get)(
914 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -0700915 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
916 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000917 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700918 {
919 return;
920 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700921 if (systemName != "system")
922 {
923 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
924 systemName);
925 return;
926 }
927
Ed Tanous002d39b2022-05-31 08:59:27 -0700928 // Collections don't include the static data added by SubRoute
929 // because it has a duplicate entry for members
930 asyncResp->res.jsonValue["@odata.type"] =
931 "#LogServiceCollection.LogServiceCollection";
932 asyncResp->res.jsonValue["@odata.id"] =
933 "/redfish/v1/Systems/system/LogServices";
934 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
935 asyncResp->res.jsonValue["Description"] =
936 "Collection of LogServices for this Computer System";
937 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
938 logServiceArray = nlohmann::json::array();
939 nlohmann::json::object_t eventLog;
940 eventLog["@odata.id"] =
941 "/redfish/v1/Systems/system/LogServices/EventLog";
942 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500943#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700944 nlohmann::json::object_t dumpLog;
945 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
946 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -0600947#endif
948
Jason M. Billsd53dd412019-02-12 17:16:22 -0800949#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700950 nlohmann::json::object_t crashdump;
951 crashdump["@odata.id"] =
952 "/redfish/v1/Systems/system/LogServices/Crashdump";
953 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -0800954#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800955
956#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -0700957 nlohmann::json::object_t hostlogger;
958 hostlogger["@odata.id"] =
959 "/redfish/v1/Systems/system/LogServices/HostLogger";
960 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +0800961#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700962 asyncResp->res.jsonValue["Members@odata.count"] =
963 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800964
Ed Tanous002d39b2022-05-31 08:59:27 -0700965 crow::connections::systemBus->async_method_call(
966 [asyncResp](const boost::system::error_code ec,
967 const dbus::utility::MapperGetSubTreePathsResponse&
968 subtreePath) {
969 if (ec)
970 {
971 BMCWEB_LOG_ERROR << ec;
972 return;
973 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700974
Ed Tanous002d39b2022-05-31 08:59:27 -0700975 for (const auto& pathStr : subtreePath)
976 {
977 if (pathStr.find("PostCode") != std::string::npos)
978 {
979 nlohmann::json& logServiceArrayLocal =
980 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -0700981 nlohmann::json::object_t member;
982 member["@odata.id"] =
983 "/redfish/v1/Systems/system/LogServices/PostCodes";
984
985 logServiceArrayLocal.push_back(std::move(member));
986
Ed Tanous002d39b2022-05-31 08:59:27 -0700987 asyncResp->res.jsonValue["Members@odata.count"] =
988 logServiceArrayLocal.size();
989 return;
990 }
991 }
992 },
993 "xyz.openbmc_project.ObjectMapper",
994 "/xyz/openbmc_project/object_mapper",
995 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
996 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -0700997 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700998}
999
1000inline void requestRoutesEventLogService(App& app)
1001{
Ed Tanous22d268c2022-05-19 09:39:07 -07001002 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001003 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001004 .methods(boost::beast::http::verb::get)(
1005 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001006 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1007 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001008 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001009 {
1010 return;
1011 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001012 if (systemName != "system")
1013 {
1014 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1015 systemName);
1016 return;
1017 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001018 asyncResp->res.jsonValue["@odata.id"] =
1019 "/redfish/v1/Systems/system/LogServices/EventLog";
1020 asyncResp->res.jsonValue["@odata.type"] =
1021 "#LogService.v1_1_0.LogService";
1022 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1023 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1024 asyncResp->res.jsonValue["Id"] = "EventLog";
1025 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301026
Ed Tanous002d39b2022-05-31 08:59:27 -07001027 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001028 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301029
Ed Tanous002d39b2022-05-31 08:59:27 -07001030 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1031 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1032 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301033
Ed Tanous002d39b2022-05-31 08:59:27 -07001034 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1035 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1036 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001037
Ed Tanous002d39b2022-05-31 08:59:27 -07001038 {"target",
1039 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001040 });
1041}
1042
1043inline void requestRoutesJournalEventLogClear(App& app)
1044{
Jason M. Bills4978b632022-02-22 14:17:43 -08001045 BMCWEB_ROUTE(
1046 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001047 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001048 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001049 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001050 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001051 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1052 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001053 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001054 {
1055 return;
1056 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001057 if (systemName != "system")
1058 {
1059 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1060 systemName);
1061 return;
1062 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001063 // Clear the EventLog by deleting the log files
1064 std::vector<std::filesystem::path> redfishLogFiles;
1065 if (getRedfishLogFiles(redfishLogFiles))
1066 {
1067 for (const std::filesystem::path& file : redfishLogFiles)
1068 {
1069 std::error_code ec;
1070 std::filesystem::remove(file, ec);
1071 }
1072 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001073
Ed Tanous002d39b2022-05-31 08:59:27 -07001074 // Reload rsyslog so it knows to start new log files
1075 crow::connections::systemBus->async_method_call(
1076 [asyncResp](const boost::system::error_code ec) {
1077 if (ec)
1078 {
1079 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1080 messages::internalError(asyncResp->res);
1081 return;
1082 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001083
Ed Tanous002d39b2022-05-31 08:59:27 -07001084 messages::success(asyncResp->res);
1085 },
1086 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1087 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1088 "replace");
1089 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001090}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001091
Jason M. Billsac992cd2022-06-24 13:31:46 -07001092enum class LogParseError
1093{
1094 success,
1095 parseFailed,
1096 messageIdNotInRegistry,
1097};
1098
1099static LogParseError
1100 fillEventLogEntryJson(const std::string& logEntryID,
1101 const std::string& logEntry,
1102 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001103{
Jason M. Bills95820182019-04-22 16:25:34 -07001104 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001105 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001106 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001107 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001108 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001109 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001110 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001111 std::string timestamp = logEntry.substr(0, space);
1112 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001113 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001114 if (entryStart == std::string::npos)
1115 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001116 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001117 }
1118 std::string_view entry(logEntry);
1119 entry.remove_prefix(entryStart);
1120 // Use split to separate the entry into its fields
1121 std::vector<std::string> logEntryFields;
1122 boost::split(logEntryFields, entry, boost::is_any_of(","),
1123 boost::token_compress_on);
1124 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001125 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001126 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001127 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001128 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001129 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001130
Jason M. Bills4851d452019-03-28 11:27:48 -07001131 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001132 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001133
Sui Chen54417b02022-03-24 14:59:52 -07001134 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001135 {
Sui Chen54417b02022-03-24 14:59:52 -07001136 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001137 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001138 }
1139
Sui Chen54417b02022-03-24 14:59:52 -07001140 std::string msg = message->message;
1141
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001142 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001143 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001144 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001145 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001146 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001147 // If the first string is empty, assume there are no MessageArgs
1148 std::size_t messageArgsSize = 0;
1149 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001150 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001151 messageArgsSize = logEntryFields.size() - 1;
1152 }
1153
Ed Tanous23a21a12020-07-25 04:45:05 +00001154 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001155
1156 // Fill the MessageArgs into the Message
1157 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001158 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001159 {
1160 std::string argStr = "%" + std::to_string(++i);
1161 size_t argPos = msg.find(argStr);
1162 if (argPos != std::string::npos)
1163 {
1164 msg.replace(argPos, argStr.length(), messageArg);
1165 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001166 }
1167 }
1168
Jason M. Bills95820182019-04-22 16:25:34 -07001169 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1170 // format which matches the Redfish format except for the fractional seconds
1171 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001172 std::size_t dot = timestamp.find_first_of('.');
1173 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001174 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001175 {
Jason M. Bills95820182019-04-22 16:25:34 -07001176 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001177 }
1178
1179 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001180 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001181 logEntryJson["@odata.id"] =
1182 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1183 logEntryJson["Name"] = "System Event Log Entry";
1184 logEntryJson["Id"] = logEntryID;
1185 logEntryJson["Message"] = std::move(msg);
1186 logEntryJson["MessageId"] = std::move(messageID);
1187 logEntryJson["MessageArgs"] = messageArgs;
1188 logEntryJson["EntryType"] = "Event";
1189 logEntryJson["Severity"] = message->messageSeverity;
1190 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001191 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001192}
1193
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001194inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001195{
Ed Tanous22d268c2022-05-19 09:39:07 -07001196 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001197 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001198 .methods(boost::beast::http::verb::get)(
1199 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001200 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1201 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001202 query_param::QueryCapabilities capabilities = {
1203 .canDelegateTop = true,
1204 .canDelegateSkip = true,
1205 };
1206 query_param::Query delegatedQuery;
1207 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001208 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001209 {
1210 return;
1211 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001212 if (systemName != "system")
1213 {
1214 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1215 systemName);
1216 return;
1217 }
1218
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001219 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001220 size_t skip = delegatedQuery.skip.value_or(0);
1221
Ed Tanous002d39b2022-05-31 08:59:27 -07001222 // Collections don't include the static data added by SubRoute
1223 // because it has a duplicate entry for members
1224 asyncResp->res.jsonValue["@odata.type"] =
1225 "#LogEntryCollection.LogEntryCollection";
1226 asyncResp->res.jsonValue["@odata.id"] =
1227 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1228 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1229 asyncResp->res.jsonValue["Description"] =
1230 "Collection of System Event Log Entries";
1231
1232 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1233 logEntryArray = nlohmann::json::array();
1234 // Go through the log files and create a unique ID for each
1235 // entry
1236 std::vector<std::filesystem::path> redfishLogFiles;
1237 getRedfishLogFiles(redfishLogFiles);
1238 uint64_t entryCount = 0;
1239 std::string logEntry;
1240
1241 // Oldest logs are in the last file, so start there and loop
1242 // backwards
1243 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1244 it++)
1245 {
1246 std::ifstream logStream(*it);
1247 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001248 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001249 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001250 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001251
Ed Tanous002d39b2022-05-31 08:59:27 -07001252 // Reset the unique ID on the first entry
1253 bool firstEntry = true;
1254 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001255 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001256 std::string idStr;
1257 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001258 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001259 continue;
1260 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001261 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001262
Jason M. Billsde703c52022-06-23 14:19:04 -07001263 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001264 LogParseError status =
1265 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1266 if (status == LogParseError::messageIdNotInRegistry)
1267 {
1268 continue;
1269 }
1270 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001271 {
1272 messages::internalError(asyncResp->res);
1273 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001274 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001275
Jason M. Billsde703c52022-06-23 14:19:04 -07001276 entryCount++;
1277 // Handle paging using skip (number of entries to skip from the
1278 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001279 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001280 {
1281 continue;
1282 }
1283
1284 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001285 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001286 }
1287 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001288 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001289 {
1290 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1291 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001292 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001293 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001294 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001295}
Chicago Duan336e96c2019-07-15 14:22:08 +08001296
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001297inline void requestRoutesJournalEventLogEntry(App& app)
1298{
1299 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001300 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001301 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001302 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001303 [&app](const crow::Request& req,
1304 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001305 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001306 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001307 {
1308 return;
1309 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001310
1311 if (systemName != "system")
1312 {
1313 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1314 systemName);
1315 return;
1316 }
1317
Ed Tanous002d39b2022-05-31 08:59:27 -07001318 const std::string& targetID = param;
1319
1320 // Go through the log files and check the unique ID for each
1321 // entry to find the target entry
1322 std::vector<std::filesystem::path> redfishLogFiles;
1323 getRedfishLogFiles(redfishLogFiles);
1324 std::string logEntry;
1325
1326 // Oldest logs are in the last file, so start there and loop
1327 // backwards
1328 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1329 it++)
1330 {
1331 std::ifstream logStream(*it);
1332 if (!logStream.is_open())
1333 {
1334 continue;
1335 }
1336
1337 // Reset the unique ID on the first entry
1338 bool firstEntry = true;
1339 while (std::getline(logStream, logEntry))
1340 {
1341 std::string idStr;
1342 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001343 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001344 continue;
1345 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001346 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001347
1348 if (idStr == targetID)
1349 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001350 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001351 LogParseError status =
1352 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1353 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001354 {
1355 messages::internalError(asyncResp->res);
1356 return;
1357 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001358 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001359 return;
1360 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001361 }
1362 }
1363 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08001364 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07001365 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001366}
1367
1368inline void requestRoutesDBusEventLogEntryCollection(App& app)
1369{
Ed Tanous22d268c2022-05-19 09:39:07 -07001370 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001371 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001372 .methods(boost::beast::http::verb::get)(
1373 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001374 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1375 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001376 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001377 {
1378 return;
1379 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001380 if (systemName != "system")
1381 {
1382 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1383 systemName);
1384 return;
1385 }
1386
Ed Tanous002d39b2022-05-31 08:59:27 -07001387 // Collections don't include the static data added by SubRoute
1388 // because it has a duplicate entry for members
1389 asyncResp->res.jsonValue["@odata.type"] =
1390 "#LogEntryCollection.LogEntryCollection";
1391 asyncResp->res.jsonValue["@odata.id"] =
1392 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1393 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1394 asyncResp->res.jsonValue["Description"] =
1395 "Collection of System Event Log Entries";
1396
1397 // DBus implementation of EventLog/Entries
1398 // Make call to Logging Service to find all log entry objects
1399 crow::connections::systemBus->async_method_call(
1400 [asyncResp](const boost::system::error_code ec,
1401 const dbus::utility::ManagedObjectType& resp) {
1402 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001403 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001404 // TODO Handle for specific error code
1405 BMCWEB_LOG_ERROR
1406 << "getLogEntriesIfaceData resp_handler got error " << ec;
1407 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001408 return;
1409 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001410 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1411 entriesArray = nlohmann::json::array();
1412 for (const auto& objectPath : resp)
1413 {
1414 const uint32_t* id = nullptr;
1415 const uint64_t* timestamp = nullptr;
1416 const uint64_t* updateTimestamp = nullptr;
1417 const std::string* severity = nullptr;
1418 const std::string* message = nullptr;
1419 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001420 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001421 bool resolved = false;
1422 for (const auto& interfaceMap : objectPath.second)
1423 {
1424 if (interfaceMap.first ==
1425 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001426 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001427 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001428 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001429 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001430 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001431 id = std::get_if<uint32_t>(&propertyMap.second);
1432 }
1433 else if (propertyMap.first == "Timestamp")
1434 {
1435 timestamp =
1436 std::get_if<uint64_t>(&propertyMap.second);
1437 }
1438 else if (propertyMap.first == "UpdateTimestamp")
1439 {
1440 updateTimestamp =
1441 std::get_if<uint64_t>(&propertyMap.second);
1442 }
1443 else if (propertyMap.first == "Severity")
1444 {
1445 severity = std::get_if<std::string>(
1446 &propertyMap.second);
1447 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001448 else if (propertyMap.first == "Resolution")
1449 {
1450 resolution = std::get_if<std::string>(
1451 &propertyMap.second);
1452 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001453 else if (propertyMap.first == "Message")
1454 {
1455 message = std::get_if<std::string>(
1456 &propertyMap.second);
1457 }
1458 else if (propertyMap.first == "Resolved")
1459 {
1460 const bool* resolveptr =
1461 std::get_if<bool>(&propertyMap.second);
1462 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001463 {
1464 messages::internalError(asyncResp->res);
1465 return;
1466 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001467 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001468 }
1469 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001470 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001471 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001472 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001473 messages::internalError(asyncResp->res);
1474 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001475 }
1476 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001477 else if (interfaceMap.first ==
1478 "xyz.openbmc_project.Common.FilePath")
1479 {
1480 for (const auto& propertyMap : interfaceMap.second)
1481 {
1482 if (propertyMap.first == "Path")
1483 {
1484 filePath = std::get_if<std::string>(
1485 &propertyMap.second);
1486 }
1487 }
1488 }
1489 }
1490 // Object path without the
1491 // xyz.openbmc_project.Logging.Entry interface, ignore
1492 // and continue.
1493 if (id == nullptr || message == nullptr ||
1494 severity == nullptr || timestamp == nullptr ||
1495 updateTimestamp == nullptr)
1496 {
1497 continue;
1498 }
1499 entriesArray.push_back({});
1500 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001501 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001502 thisEntry["@odata.id"] =
1503 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1504 std::to_string(*id);
1505 thisEntry["Name"] = "System Event Log Entry";
1506 thisEntry["Id"] = std::to_string(*id);
1507 thisEntry["Message"] = *message;
1508 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001509 if ((resolution != nullptr) && (!(*resolution).empty()))
1510 {
1511 thisEntry["Resolution"] = *resolution;
1512 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001513 thisEntry["EntryType"] = "Event";
1514 thisEntry["Severity"] =
1515 translateSeverityDbusToRedfish(*severity);
1516 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001517 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001518 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001519 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001520 if (filePath != nullptr)
1521 {
1522 thisEntry["AdditionalDataURI"] =
1523 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1524 std::to_string(*id) + "/attachment";
1525 }
1526 }
1527 std::sort(
1528 entriesArray.begin(), entriesArray.end(),
1529 [](const nlohmann::json& left, const nlohmann::json& right) {
1530 return (left["Id"] <= right["Id"]);
1531 });
1532 asyncResp->res.jsonValue["Members@odata.count"] =
1533 entriesArray.size();
1534 },
1535 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1536 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001537 });
1538}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001539
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001540inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001541{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001542 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001543 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001544 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001545 .methods(boost::beast::http::verb::get)(
1546 [&app](const crow::Request& req,
1547 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001548 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001549 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001550 {
1551 return;
1552 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001553 if (systemName != "system")
1554 {
1555 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1556 systemName);
1557 return;
1558 }
1559
Ed Tanous002d39b2022-05-31 08:59:27 -07001560 std::string entryID = param;
1561 dbus::utility::escapePathForDbus(entryID);
1562
1563 // DBus implementation of EventLog/Entries
1564 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001565 sdbusplus::asio::getAllProperties(
1566 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1567 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001568 [asyncResp, entryID](const boost::system::error_code ec,
1569 const dbus::utility::DBusPropertiesMap& resp) {
1570 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001571 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001572 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1573 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001574 return;
1575 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001576 if (ec)
1577 {
1578 BMCWEB_LOG_ERROR
1579 << "EventLogEntry (DBus) resp_handler got error " << ec;
1580 messages::internalError(asyncResp->res);
1581 return;
1582 }
1583 const uint32_t* id = nullptr;
1584 const uint64_t* timestamp = nullptr;
1585 const uint64_t* updateTimestamp = nullptr;
1586 const std::string* severity = nullptr;
1587 const std::string* message = nullptr;
1588 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001589 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001590 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001591
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001592 const bool success = sdbusplus::unpackPropertiesNoThrow(
1593 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1594 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001595 severity, "Message", message, "Resolved", resolved,
1596 "Resolution", resolution, "Path", filePath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001597
1598 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001599 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001600 messages::internalError(asyncResp->res);
1601 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001602 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001603
Ed Tanous002d39b2022-05-31 08:59:27 -07001604 if (id == nullptr || message == nullptr || severity == nullptr ||
1605 timestamp == nullptr || updateTimestamp == nullptr)
1606 {
1607 messages::internalError(asyncResp->res);
1608 return;
1609 }
1610 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001611 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001612 asyncResp->res.jsonValue["@odata.id"] =
1613 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1614 std::to_string(*id);
1615 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1616 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1617 asyncResp->res.jsonValue["Message"] = *message;
1618 asyncResp->res.jsonValue["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001619 if ((resolution != nullptr) && (!(*resolution).empty()))
1620 {
1621 asyncResp->res.jsonValue["Resolution"] = *resolution;
1622 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001623 asyncResp->res.jsonValue["EntryType"] = "Event";
1624 asyncResp->res.jsonValue["Severity"] =
1625 translateSeverityDbusToRedfish(*severity);
1626 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001627 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001628 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001629 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001630 if (filePath != nullptr)
1631 {
1632 asyncResp->res.jsonValue["AdditionalDataURI"] =
1633 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1634 std::to_string(*id) + "/attachment";
1635 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001636 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001637 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001638
1639 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001640 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001641 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001642 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001643 [&app](const crow::Request& req,
1644 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001645 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001646 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001647 {
1648 return;
1649 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001650 if (systemName != "system")
1651 {
1652 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1653 systemName);
1654 return;
1655 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001656 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001657
Ed Tanous002d39b2022-05-31 08:59:27 -07001658 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1659 resolved))
1660 {
1661 return;
1662 }
1663 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001664
Ed Tanous002d39b2022-05-31 08:59:27 -07001665 crow::connections::systemBus->async_method_call(
1666 [asyncResp, entryId](const boost::system::error_code ec) {
1667 if (ec)
1668 {
1669 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1670 messages::internalError(asyncResp->res);
1671 return;
1672 }
1673 },
1674 "xyz.openbmc_project.Logging",
1675 "/xyz/openbmc_project/logging/entry/" + entryId,
1676 "org.freedesktop.DBus.Properties", "Set",
1677 "xyz.openbmc_project.Logging.Entry", "Resolved",
1678 dbus::utility::DbusVariantType(*resolved));
1679 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001680
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001681 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001682 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001683 .privileges(redfish::privileges::deleteLogEntry)
1684
Ed Tanous002d39b2022-05-31 08:59:27 -07001685 .methods(boost::beast::http::verb::delete_)(
1686 [&app](const crow::Request& req,
1687 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001688 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001689 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001690 {
1691 return;
1692 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001693 if (systemName != "system")
1694 {
1695 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1696 systemName);
1697 return;
1698 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001699 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1700
1701 std::string entryID = param;
1702
1703 dbus::utility::escapePathForDbus(entryID);
1704
1705 // Process response from Logging service.
1706 auto respHandler =
1707 [asyncResp, entryID](const boost::system::error_code ec) {
1708 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1709 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001710 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001711 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001712 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001713 messages::resourceNotFound(asyncResp->res, "LogEntry",
1714 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001715 return;
1716 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001717 // TODO Handle for specific error code
1718 BMCWEB_LOG_ERROR
1719 << "EventLogEntry (DBus) doDelete respHandler got error "
1720 << ec;
1721 asyncResp->res.result(
1722 boost::beast::http::status::internal_server_error);
1723 return;
1724 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001725
Ed Tanous002d39b2022-05-31 08:59:27 -07001726 asyncResp->res.result(boost::beast::http::status::ok);
1727 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001728
Ed Tanous002d39b2022-05-31 08:59:27 -07001729 // Make call to Logging service to request Delete Log
1730 crow::connections::systemBus->async_method_call(
1731 respHandler, "xyz.openbmc_project.Logging",
1732 "/xyz/openbmc_project/logging/entry/" + entryID,
1733 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001734 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001735}
1736
1737inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001738{
George Liu0fda0f12021-11-16 10:06:17 +08001739 BMCWEB_ROUTE(
1740 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001741 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001742 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001743 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001744 [&app](const crow::Request& req,
1745 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001746 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001747 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001748 {
1749 return;
1750 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001751 if (http_helpers::isContentTypeAllowed(
1752 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001753 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001754 {
1755 asyncResp->res.result(boost::beast::http::status::bad_request);
1756 return;
1757 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001758 if (systemName != "system")
1759 {
1760 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1761 systemName);
1762 return;
1763 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001764
Ed Tanous002d39b2022-05-31 08:59:27 -07001765 std::string entryID = param;
1766 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001767
Ed Tanous002d39b2022-05-31 08:59:27 -07001768 crow::connections::systemBus->async_method_call(
1769 [asyncResp, entryID](const boost::system::error_code ec,
1770 const sdbusplus::message::unix_fd& unixfd) {
1771 if (ec.value() == EBADR)
1772 {
1773 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1774 entryID);
1775 return;
1776 }
1777 if (ec)
1778 {
1779 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1780 messages::internalError(asyncResp->res);
1781 return;
1782 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001783
Ed Tanous002d39b2022-05-31 08:59:27 -07001784 int fd = -1;
1785 fd = dup(unixfd);
1786 if (fd == -1)
1787 {
1788 messages::internalError(asyncResp->res);
1789 return;
1790 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001791
Ed Tanous002d39b2022-05-31 08:59:27 -07001792 long long int size = lseek(fd, 0, SEEK_END);
1793 if (size == -1)
1794 {
1795 messages::internalError(asyncResp->res);
1796 return;
1797 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001798
Ed Tanous002d39b2022-05-31 08:59:27 -07001799 // Arbitrary max size of 64kb
1800 constexpr int maxFileSize = 65536;
1801 if (size > maxFileSize)
1802 {
1803 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1804 << maxFileSize;
1805 messages::internalError(asyncResp->res);
1806 return;
1807 }
1808 std::vector<char> data(static_cast<size_t>(size));
1809 long long int rc = lseek(fd, 0, SEEK_SET);
1810 if (rc == -1)
1811 {
1812 messages::internalError(asyncResp->res);
1813 return;
1814 }
1815 rc = read(fd, data.data(), data.size());
1816 if ((rc == -1) || (rc != size))
1817 {
1818 messages::internalError(asyncResp->res);
1819 return;
1820 }
1821 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001822
Ed Tanous002d39b2022-05-31 08:59:27 -07001823 std::string_view strData(data.data(), data.size());
1824 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001825
Ed Tanousd9f6c622022-03-17 09:12:17 -07001826 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001827 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001828 asyncResp->res.addHeader(
1829 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 asyncResp->res.body() = std::move(output);
1831 },
1832 "xyz.openbmc_project.Logging",
1833 "/xyz/openbmc_project/logging/entry/" + entryID,
1834 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1835 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001836}
1837
Spencer Kub7028eb2021-10-26 15:27:35 +08001838constexpr const char* hostLoggerFolderPath = "/var/log/console";
1839
1840inline bool
1841 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1842 std::vector<std::filesystem::path>& hostLoggerFiles)
1843{
1844 std::error_code ec;
1845 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1846 if (ec)
1847 {
1848 BMCWEB_LOG_ERROR << ec.message();
1849 return false;
1850 }
1851 for (const std::filesystem::directory_entry& it : logPath)
1852 {
1853 std::string filename = it.path().filename();
1854 // Prefix of each log files is "log". Find the file and save the
1855 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07001856 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08001857 {
1858 hostLoggerFiles.emplace_back(it.path());
1859 }
1860 }
1861 // As the log files rotate, they are appended with a ".#" that is higher for
1862 // the older logs. Since we start from oldest logs, sort the name in
1863 // descending order.
1864 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1865 AlphanumLess<std::string>());
1866
1867 return true;
1868}
1869
Ed Tanous02cad962022-06-30 16:50:15 -07001870inline bool getHostLoggerEntries(
1871 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
1872 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001873{
1874 GzFileReader logFile;
1875
1876 // Go though all log files and expose host logs.
1877 for (const std::filesystem::path& it : hostLoggerFiles)
1878 {
1879 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1880 {
1881 BMCWEB_LOG_ERROR << "fail to expose host logs";
1882 return false;
1883 }
1884 }
1885 // Get lastMessage from constructor by getter
1886 std::string lastMessage = logFile.getLastMessage();
1887 if (!lastMessage.empty())
1888 {
1889 logCount++;
1890 if (logCount > skip && logCount <= (skip + top))
1891 {
1892 logEntries.push_back(lastMessage);
1893 }
1894 }
1895 return true;
1896}
1897
1898inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1899 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07001900 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08001901{
1902 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05001903 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07001904 logEntryJson["@odata.id"] =
1905 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1906 logEntryID;
1907 logEntryJson["Name"] = "Host Logger Entry";
1908 logEntryJson["Id"] = logEntryID;
1909 logEntryJson["Message"] = msg;
1910 logEntryJson["EntryType"] = "Oem";
1911 logEntryJson["Severity"] = "OK";
1912 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08001913}
1914
1915inline void requestRoutesSystemHostLogger(App& app)
1916{
Ed Tanous22d268c2022-05-19 09:39:07 -07001917 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08001918 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07001919 .methods(boost::beast::http::verb::get)(
1920 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001921 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1922 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001923 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001924 {
1925 return;
1926 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001927 if (systemName != "system")
1928 {
1929 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1930 systemName);
1931 return;
1932 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001933 asyncResp->res.jsonValue["@odata.id"] =
1934 "/redfish/v1/Systems/system/LogServices/HostLogger";
1935 asyncResp->res.jsonValue["@odata.type"] =
1936 "#LogService.v1_1_0.LogService";
1937 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1938 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1939 asyncResp->res.jsonValue["Id"] = "HostLogger";
1940 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1941 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1942 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001943}
1944
1945inline void requestRoutesSystemHostLoggerCollection(App& app)
1946{
1947 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001948 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08001949 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001950 .methods(boost::beast::http::verb::get)(
1951 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001952 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1953 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001954 query_param::QueryCapabilities capabilities = {
1955 .canDelegateTop = true,
1956 .canDelegateSkip = true,
1957 };
1958 query_param::Query delegatedQuery;
1959 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001960 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001961 {
1962 return;
1963 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001964 if (systemName != "system")
1965 {
1966 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1967 systemName);
1968 return;
1969 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001970 asyncResp->res.jsonValue["@odata.id"] =
1971 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1972 asyncResp->res.jsonValue["@odata.type"] =
1973 "#LogEntryCollection.LogEntryCollection";
1974 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1975 asyncResp->res.jsonValue["Description"] =
1976 "Collection of HostLogger Entries";
1977 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1978 logEntryArray = nlohmann::json::array();
1979 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001980
Ed Tanous002d39b2022-05-31 08:59:27 -07001981 std::vector<std::filesystem::path> hostLoggerFiles;
1982 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1983 {
1984 BMCWEB_LOG_ERROR << "fail to get host log file path";
1985 return;
1986 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07001987 // If we weren't provided top and skip limits, use the defaults.
1988 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001989 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07001990 size_t logCount = 0;
1991 // This vector only store the entries we want to expose that
1992 // control by skip and top.
1993 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001994 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
1995 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07001996 {
1997 messages::internalError(asyncResp->res);
1998 return;
1999 }
2000 // If vector is empty, that means skip value larger than total
2001 // log count
2002 if (logEntries.empty())
2003 {
2004 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2005 return;
2006 }
2007 if (!logEntries.empty())
2008 {
2009 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002010 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002011 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002012 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2013 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002014 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002015 }
2016
Ed Tanous002d39b2022-05-31 08:59:27 -07002017 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002018 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002019 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002020 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2021 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002022 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002023 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002024 }
George Liu0fda0f12021-11-16 10:06:17 +08002025 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002026}
2027
2028inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2029{
2030 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002031 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002032 .privileges(redfish::privileges::getLogEntry)
2033 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002034 [&app](const crow::Request& req,
2035 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002036 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002037 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002038 {
2039 return;
2040 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002041 if (systemName != "system")
2042 {
2043 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2044 systemName);
2045 return;
2046 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002047 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002048
Ed Tanous002d39b2022-05-31 08:59:27 -07002049 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002050
Ed Tanous002d39b2022-05-31 08:59:27 -07002051 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2052 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002053
Ed Tanous002d39b2022-05-31 08:59:27 -07002054 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002055 if (ec == std::errc::invalid_argument ||
2056 ec == std::errc::result_out_of_range)
Ed Tanous002d39b2022-05-31 08:59:27 -07002057 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002058 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002059 return;
2060 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002061
Ed Tanous002d39b2022-05-31 08:59:27 -07002062 std::vector<std::filesystem::path> hostLoggerFiles;
2063 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2064 {
2065 BMCWEB_LOG_ERROR << "fail to get host log file path";
2066 return;
2067 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002068
Ed Tanous002d39b2022-05-31 08:59:27 -07002069 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002070 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002071 std::vector<std::string> logEntries;
2072 // We can get specific entry by skip and top. For example, if we
2073 // want to get nth entry, we can set skip = n-1 and top = 1 to
2074 // get that entry
2075 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2076 logCount))
2077 {
2078 messages::internalError(asyncResp->res);
2079 return;
2080 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002081
Ed Tanous002d39b2022-05-31 08:59:27 -07002082 if (!logEntries.empty())
2083 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002084 nlohmann::json::object_t hostLogEntry;
2085 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2086 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002087 return;
2088 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002089
Ed Tanous002d39b2022-05-31 08:59:27 -07002090 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002091 messages::resourceNotFound(asyncResp->res, "LogEntry", param);
Ed Tanous002d39b2022-05-31 08:59:27 -07002092 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002093}
2094
Claire Weinanfdd26902022-03-01 14:18:25 -08002095constexpr char const* dumpManagerIface =
2096 "xyz.openbmc_project.Collection.DeleteAll";
Claire Weinandd72e872022-08-15 14:20:06 -07002097inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002098 crow::App& app, const crow::Request& req,
2099 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2100{
2101 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2102 {
2103 return;
2104 }
2105 // Collections don't include the static data added by SubRoute
2106 // because it has a duplicate entry for members
2107 asyncResp->res.jsonValue["@odata.type"] =
2108 "#LogServiceCollection.LogServiceCollection";
2109 asyncResp->res.jsonValue["@odata.id"] =
2110 "/redfish/v1/Managers/bmc/LogServices";
2111 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2112 asyncResp->res.jsonValue["Description"] =
2113 "Collection of LogServices for this Manager";
2114 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2115 logServiceArray = nlohmann::json::array();
2116
2117#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002118 nlohmann::json::object_t journal;
2119 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2120 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002121#endif
2122
2123 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2124
2125#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2126 auto respHandler =
2127 [asyncResp](
2128 const boost::system::error_code ec,
2129 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2130 if (ec)
2131 {
2132 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002133 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002134 << ec;
2135 // Assume that getting an error simply means there are no dump
2136 // LogServices. Return without adding any error response.
2137 return;
2138 }
2139
2140 nlohmann::json& logServiceArrayLocal =
2141 asyncResp->res.jsonValue["Members"];
2142
2143 for (const std::string& path : subTreePaths)
2144 {
2145 if (path == "/xyz/openbmc_project/dump/bmc")
2146 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002147 nlohmann::json::object_t member;
2148 member["@odata.id"] =
2149 "/redfish/v1/Managers/bmc/LogServices/Dump";
2150 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002151 }
2152 else if (path == "/xyz/openbmc_project/dump/faultlog")
2153 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002154 nlohmann::json::object_t member;
2155 member["@odata.id"] =
2156 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2157 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002158 }
2159 }
2160
2161 asyncResp->res.jsonValue["Members@odata.count"] =
2162 logServiceArrayLocal.size();
2163 };
2164
2165 crow::connections::systemBus->async_method_call(
2166 respHandler, "xyz.openbmc_project.ObjectMapper",
2167 "/xyz/openbmc_project/object_mapper",
2168 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2169 "/xyz/openbmc_project/dump", 0,
2170 std::array<const char*, 1>{dumpManagerIface});
2171#endif
2172}
2173
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002174inline void requestRoutesBMCLogServiceCollection(App& app)
2175{
2176 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002177 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002178 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002179 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002180}
Ed Tanous1da66f72018-07-27 16:13:37 -07002181
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002182inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002183{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002184 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002185 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002186 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002187 [&app](const crow::Request& req,
2188 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002189 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002190 {
2191 return;
2192 }
2193 asyncResp->res.jsonValue["@odata.type"] =
2194 "#LogService.v1_1_0.LogService";
2195 asyncResp->res.jsonValue["@odata.id"] =
2196 "/redfish/v1/Managers/bmc/LogServices/Journal";
2197 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2198 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2199 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2200 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302201
Ed Tanous002d39b2022-05-31 08:59:27 -07002202 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002203 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002204 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2205 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2206 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302207
Ed Tanous002d39b2022-05-31 08:59:27 -07002208 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2209 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2210 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002211}
Jason M. Billse1f26342018-07-18 12:12:00 -07002212
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002213static int
2214 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2215 sd_journal* journal,
2216 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002217{
2218 // Get the Log Entry contents
2219 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002220
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002221 std::string message;
2222 std::string_view syslogID;
2223 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2224 if (ret < 0)
2225 {
2226 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2227 << strerror(-ret);
2228 }
2229 if (!syslogID.empty())
2230 {
2231 message += std::string(syslogID) + ": ";
2232 }
2233
Ed Tanous39e77502019-03-04 17:35:53 -08002234 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002235 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002236 if (ret < 0)
2237 {
2238 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2239 return 1;
2240 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002241 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002242
2243 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002244 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002245 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002246 if (ret < 0)
2247 {
2248 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002249 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002250
2251 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002252 std::string entryTimeStr;
2253 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002254 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002255 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002256 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002257
2258 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002259 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002260 bmcJournalLogEntryJson["@odata.id"] =
2261 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2262 bmcJournalLogEntryID;
2263 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2264 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2265 bmcJournalLogEntryJson["Message"] = std::move(message);
2266 bmcJournalLogEntryJson["EntryType"] = "Oem";
2267 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2268 : severity <= 4 ? "Warning"
2269 : "OK";
2270 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2271 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002272 return 0;
2273}
2274
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002275inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002276{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002277 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002278 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002279 .methods(boost::beast::http::verb::get)(
2280 [&app](const crow::Request& req,
2281 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2282 query_param::QueryCapabilities capabilities = {
2283 .canDelegateTop = true,
2284 .canDelegateSkip = true,
2285 };
2286 query_param::Query delegatedQuery;
2287 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002288 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002289 {
2290 return;
2291 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002292
2293 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002294 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002295
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 // Collections don't include the static data added by SubRoute
2297 // because it has a duplicate entry for members
2298 asyncResp->res.jsonValue["@odata.type"] =
2299 "#LogEntryCollection.LogEntryCollection";
2300 asyncResp->res.jsonValue["@odata.id"] =
2301 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2302 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2303 asyncResp->res.jsonValue["Description"] =
2304 "Collection of BMC Journal Entries";
2305 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2306 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002307
Ed Tanous002d39b2022-05-31 08:59:27 -07002308 // Go through the journal and use the timestamp to create a
2309 // unique ID for each entry
2310 sd_journal* journalTmp = nullptr;
2311 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2312 if (ret < 0)
2313 {
2314 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2315 messages::internalError(asyncResp->res);
2316 return;
2317 }
2318 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2319 journalTmp, sd_journal_close);
2320 journalTmp = nullptr;
2321 uint64_t entryCount = 0;
2322 // Reset the unique ID on the first entry
2323 bool firstEntry = true;
2324 SD_JOURNAL_FOREACH(journal.get())
2325 {
2326 entryCount++;
2327 // Handle paging using skip (number of entries to skip from
2328 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002329 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002330 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002331 continue;
2332 }
2333
2334 std::string idStr;
2335 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2336 {
2337 continue;
2338 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002339 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002340
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002341 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002342 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2343 bmcJournalLogEntry) != 0)
2344 {
George Liu0fda0f12021-11-16 10:06:17 +08002345 messages::internalError(asyncResp->res);
2346 return;
2347 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002348 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002349 }
2350 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002351 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002352 {
2353 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2354 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002355 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002356 }
George Liu0fda0f12021-11-16 10:06:17 +08002357 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002358}
Jason M. Billse1f26342018-07-18 12:12:00 -07002359
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002360inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002361{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002362 BMCWEB_ROUTE(app,
2363 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002364 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002365 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002366 [&app](const crow::Request& req,
2367 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2368 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002369 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002370 {
2371 return;
2372 }
2373 // Convert the unique ID back to a timestamp to find the entry
2374 uint64_t ts = 0;
2375 uint64_t index = 0;
2376 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2377 {
2378 return;
2379 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002380
Ed Tanous002d39b2022-05-31 08:59:27 -07002381 sd_journal* journalTmp = nullptr;
2382 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2383 if (ret < 0)
2384 {
2385 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2386 messages::internalError(asyncResp->res);
2387 return;
2388 }
2389 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2390 journalTmp, sd_journal_close);
2391 journalTmp = nullptr;
2392 // Go to the timestamp in the log and move to the entry at the
2393 // index tracking the unique ID
2394 std::string idStr;
2395 bool firstEntry = true;
2396 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2397 if (ret < 0)
2398 {
2399 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2400 << strerror(-ret);
2401 messages::internalError(asyncResp->res);
2402 return;
2403 }
2404 for (uint64_t i = 0; i <= index; i++)
2405 {
2406 sd_journal_next(journal.get());
2407 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2408 {
2409 messages::internalError(asyncResp->res);
2410 return;
2411 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002412 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002413 }
2414 // Confirm that the entry ID matches what was requested
2415 if (idStr != entryID)
2416 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002417 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002418 return;
2419 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002420
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002421 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002422 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002423 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002424 {
2425 messages::internalError(asyncResp->res);
2426 return;
2427 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002428 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002429 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002430}
2431
Claire Weinanfdd26902022-03-01 14:18:25 -08002432inline void
2433 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2434 const std::string& dumpType)
2435{
2436 std::string dumpPath;
2437 std::string overWritePolicy;
2438 bool collectDiagnosticDataSupported = false;
2439
2440 if (dumpType == "BMC")
2441 {
2442 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2443 overWritePolicy = "WrapsWhenFull";
2444 collectDiagnosticDataSupported = true;
2445 }
2446 else if (dumpType == "FaultLog")
2447 {
2448 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2449 overWritePolicy = "Unknown";
2450 collectDiagnosticDataSupported = false;
2451 }
2452 else if (dumpType == "System")
2453 {
2454 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2455 overWritePolicy = "WrapsWhenFull";
2456 collectDiagnosticDataSupported = true;
2457 }
2458 else
2459 {
2460 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2461 << dumpType;
2462 messages::internalError(asyncResp->res);
2463 return;
2464 }
2465
2466 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2467 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2468 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2469 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2470 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2471 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2472
2473 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002474 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002475 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2476 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2477 redfishDateTimeOffset.second;
2478
2479 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2480 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2481 dumpPath + "/Actions/LogService.ClearLog";
2482
2483 if (collectDiagnosticDataSupported)
2484 {
2485 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2486 ["target"] =
2487 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2488 }
2489}
2490
2491inline void handleLogServicesDumpServiceGet(
2492 crow::App& app, const std::string& dumpType, const crow::Request& req,
2493 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2494{
2495 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2496 {
2497 return;
2498 }
2499 getDumpServiceInfo(asyncResp, dumpType);
2500}
2501
Ed Tanous22d268c2022-05-19 09:39:07 -07002502inline void handleLogServicesDumpServiceComputerSystemGet(
2503 crow::App& app, const crow::Request& req,
2504 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2505 const std::string& chassisId)
2506{
2507 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2508 {
2509 return;
2510 }
2511 if (chassisId != "system")
2512 {
2513 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2514 return;
2515 }
2516 getDumpServiceInfo(asyncResp, "System");
2517}
2518
Claire Weinanfdd26902022-03-01 14:18:25 -08002519inline void handleLogServicesDumpEntriesCollectionGet(
2520 crow::App& app, const std::string& dumpType, const crow::Request& req,
2521 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2522{
2523 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2524 {
2525 return;
2526 }
2527 getDumpEntryCollection(asyncResp, dumpType);
2528}
2529
Ed Tanous22d268c2022-05-19 09:39:07 -07002530inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2531 crow::App& app, const crow::Request& req,
2532 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2533 const std::string& chassisId)
2534{
2535 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2536 {
2537 return;
2538 }
2539 if (chassisId != "system")
2540 {
2541 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2542 return;
2543 }
2544 getDumpEntryCollection(asyncResp, "System");
2545}
2546
Claire Weinanfdd26902022-03-01 14:18:25 -08002547inline void handleLogServicesDumpEntryGet(
2548 crow::App& app, const std::string& dumpType, const crow::Request& req,
2549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2550 const std::string& dumpId)
2551{
2552 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2553 {
2554 return;
2555 }
2556 getDumpEntryById(asyncResp, dumpId, dumpType);
2557}
Ed Tanous22d268c2022-05-19 09:39:07 -07002558inline void handleLogServicesDumpEntryComputerSystemGet(
2559 crow::App& app, const crow::Request& req,
2560 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2561 const std::string& chassisId, const std::string& dumpId)
2562{
2563 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2564 {
2565 return;
2566 }
2567 if (chassisId != "system")
2568 {
2569 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2570 return;
2571 }
2572 getDumpEntryById(asyncResp, dumpId, "System");
2573}
Claire Weinanfdd26902022-03-01 14:18:25 -08002574
2575inline void handleLogServicesDumpEntryDelete(
2576 crow::App& app, const std::string& dumpType, const crow::Request& req,
2577 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2578 const std::string& dumpId)
2579{
2580 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2581 {
2582 return;
2583 }
2584 deleteDumpEntry(asyncResp, dumpId, dumpType);
2585}
2586
Ed Tanous22d268c2022-05-19 09:39:07 -07002587inline void handleLogServicesDumpEntryComputerSystemDelete(
2588 crow::App& app, const crow::Request& req,
2589 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2590 const std::string& chassisId, const std::string& dumpId)
2591{
2592 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2593 {
2594 return;
2595 }
2596 if (chassisId != "system")
2597 {
2598 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2599 return;
2600 }
2601 deleteDumpEntry(asyncResp, dumpId, "System");
2602}
2603
Claire Weinanfdd26902022-03-01 14:18:25 -08002604inline void handleLogServicesDumpCollectDiagnosticDataPost(
2605 crow::App& app, const std::string& dumpType, const crow::Request& req,
2606 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2607{
2608 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2609 {
2610 return;
2611 }
2612 createDump(asyncResp, req, dumpType);
2613}
2614
Ed Tanous22d268c2022-05-19 09:39:07 -07002615inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2616 crow::App& app, const crow::Request& req,
2617 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2618 const std::string& chassisId)
2619{
2620 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2621 {
2622 return;
2623 }
2624 if (chassisId != "system")
2625 {
2626 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2627 return;
2628 }
2629 createDump(asyncResp, req, "System");
2630}
2631
Claire Weinanfdd26902022-03-01 14:18:25 -08002632inline void handleLogServicesDumpClearLogPost(
2633 crow::App& app, const std::string& dumpType, const crow::Request& req,
2634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2635{
2636 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2637 {
2638 return;
2639 }
2640 clearDump(asyncResp, dumpType);
2641}
2642
Ed Tanous22d268c2022-05-19 09:39:07 -07002643inline void handleLogServicesDumpClearLogComputerSystemPost(
2644 crow::App& app, const crow::Request& req,
2645 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2646 const std::string& chassisId)
2647{
2648 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2649 {
2650 return;
2651 }
2652 if (chassisId != "system")
2653 {
2654 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2655 return;
2656 }
2657 clearDump(asyncResp, "System");
2658}
2659
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002660inline void requestRoutesBMCDumpService(App& app)
2661{
2662 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002663 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002664 .methods(boost::beast::http::verb::get)(std::bind_front(
2665 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002666}
2667
2668inline void requestRoutesBMCDumpEntryCollection(App& app)
2669{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002670 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002671 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002672 .methods(boost::beast::http::verb::get)(std::bind_front(
2673 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002674}
2675
2676inline void requestRoutesBMCDumpEntry(App& app)
2677{
2678 BMCWEB_ROUTE(app,
2679 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002680 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002681 .methods(boost::beast::http::verb::get)(std::bind_front(
2682 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2683
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002684 BMCWEB_ROUTE(app,
2685 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002686 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002687 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2688 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002689}
2690
2691inline void requestRoutesBMCDumpCreate(App& app)
2692{
George Liu0fda0f12021-11-16 10:06:17 +08002693 BMCWEB_ROUTE(
2694 app,
2695 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002696 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002697 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002698 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2699 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002700}
2701
2702inline void requestRoutesBMCDumpClear(App& app)
2703{
George Liu0fda0f12021-11-16 10:06:17 +08002704 BMCWEB_ROUTE(
2705 app,
2706 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002707 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002708 .methods(boost::beast::http::verb::post)(std::bind_front(
2709 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2710}
2711
2712inline void requestRoutesFaultLogDumpService(App& app)
2713{
2714 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2715 .privileges(redfish::privileges::getLogService)
2716 .methods(boost::beast::http::verb::get)(std::bind_front(
2717 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2718}
2719
2720inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2721{
2722 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2723 .privileges(redfish::privileges::getLogEntryCollection)
2724 .methods(boost::beast::http::verb::get)(
2725 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2726 std::ref(app), "FaultLog"));
2727}
2728
2729inline void requestRoutesFaultLogDumpEntry(App& app)
2730{
2731 BMCWEB_ROUTE(app,
2732 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2733 .privileges(redfish::privileges::getLogEntry)
2734 .methods(boost::beast::http::verb::get)(std::bind_front(
2735 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2736
2737 BMCWEB_ROUTE(app,
2738 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2739 .privileges(redfish::privileges::deleteLogEntry)
2740 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2741 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2742}
2743
2744inline void requestRoutesFaultLogDumpClear(App& app)
2745{
2746 BMCWEB_ROUTE(
2747 app,
2748 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2749 .privileges(redfish::privileges::postLogService)
2750 .methods(boost::beast::http::verb::post)(std::bind_front(
2751 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002752}
2753
2754inline void requestRoutesSystemDumpService(App& app)
2755{
Ed Tanous22d268c2022-05-19 09:39:07 -07002756 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002757 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002758 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002759 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002760}
2761
2762inline void requestRoutesSystemDumpEntryCollection(App& app)
2763{
Ed Tanous22d268c2022-05-19 09:39:07 -07002764 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002765 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002766 .methods(boost::beast::http::verb::get)(std::bind_front(
2767 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2768 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002769}
2770
2771inline void requestRoutesSystemDumpEntry(App& app)
2772{
2773 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002774 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002775 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002776 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002777 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002778
2779 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002780 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002781 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002782 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002783 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002784}
2785
2786inline void requestRoutesSystemDumpCreate(App& app)
2787{
George Liu0fda0f12021-11-16 10:06:17 +08002788 BMCWEB_ROUTE(
2789 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002790 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002791 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002792 .methods(boost::beast::http::verb::post)(std::bind_front(
2793 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2794 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002795}
2796
2797inline void requestRoutesSystemDumpClear(App& app)
2798{
George Liu0fda0f12021-11-16 10:06:17 +08002799 BMCWEB_ROUTE(
2800 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002801 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002802 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002803 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002804 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002805}
2806
2807inline void requestRoutesCrashdumpService(App& app)
2808{
2809 // Note: Deviated from redfish privilege registry for GET & HEAD
2810 // method for security reasons.
2811 /**
2812 * Functions triggers appropriate requests on DBus
2813 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002814 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002815 // This is incorrect, should be:
2816 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002817 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002818 .methods(boost::beast::http::verb::get)(
2819 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002820 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2821 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002822 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002823 {
2824 return;
2825 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002826 if (systemName != "system")
2827 {
2828 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2829 systemName);
2830 return;
2831 }
2832
Ed Tanous002d39b2022-05-31 08:59:27 -07002833 // Copy over the static data to include the entries added by
2834 // SubRoute
2835 asyncResp->res.jsonValue["@odata.id"] =
2836 "/redfish/v1/Systems/system/LogServices/Crashdump";
2837 asyncResp->res.jsonValue["@odata.type"] =
2838 "#LogService.v1_2_0.LogService";
2839 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2840 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2841 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2842 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2843 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302844
Ed Tanous002d39b2022-05-31 08:59:27 -07002845 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002846 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002847 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2848 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2849 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302850
Ed Tanous002d39b2022-05-31 08:59:27 -07002851 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2852 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2853 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2854 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2855 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2856 ["target"] =
2857 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002858 });
2859}
2860
2861void inline requestRoutesCrashdumpClear(App& app)
2862{
George Liu0fda0f12021-11-16 10:06:17 +08002863 BMCWEB_ROUTE(
2864 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002865 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002866 // This is incorrect, should be:
2867 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002868 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002869 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002870 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002871 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2872 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002873 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002874 {
2875 return;
2876 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002877 if (systemName != "system")
2878 {
2879 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2880 systemName);
2881 return;
2882 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002883 crow::connections::systemBus->async_method_call(
2884 [asyncResp](const boost::system::error_code ec,
2885 const std::string&) {
2886 if (ec)
2887 {
2888 messages::internalError(asyncResp->res);
2889 return;
2890 }
2891 messages::success(asyncResp->res);
2892 },
2893 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2894 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002895}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002896
zhanghch058d1b46d2021-04-01 11:18:24 +08002897static void
2898 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2899 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002900{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002901 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002902 [asyncResp, logID,
2903 &logEntryJson](const boost::system::error_code ec,
2904 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002905 if (ec)
2906 {
2907 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2908 if (ec.value() ==
2909 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002910 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002911 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002912 }
2913 else
2914 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002915 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002916 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002917 return;
2918 }
2919
2920 std::string timestamp{};
2921 std::string filename{};
2922 std::string logfile{};
2923 parseCrashdumpParameters(params, filename, timestamp, logfile);
2924
2925 if (filename.empty() || timestamp.empty())
2926 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08002927 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07002928 return;
2929 }
2930
2931 std::string crashdumpURI =
2932 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2933 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07002934 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05002935 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002936 logEntry["@odata.id"] =
2937 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
2938 logEntry["Name"] = "CPU Crashdump";
2939 logEntry["Id"] = logID;
2940 logEntry["EntryType"] = "Oem";
2941 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
2942 logEntry["DiagnosticDataType"] = "OEM";
2943 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
2944 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002945
2946 // If logEntryJson references an array of LogEntry resources
2947 // ('Members' list), then push this as a new entry, otherwise set it
2948 // directly
2949 if (logEntryJson.is_array())
2950 {
2951 logEntryJson.push_back(logEntry);
2952 asyncResp->res.jsonValue["Members@odata.count"] =
2953 logEntryJson.size();
2954 }
2955 else
2956 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07002957 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002958 }
2959 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002960 sdbusplus::asio::getAllProperties(
2961 *crow::connections::systemBus, crashdumpObject,
2962 crashdumpPath + std::string("/") + logID, crashdumpInterface,
2963 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07002964}
2965
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002966inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002967{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002968 // Note: Deviated from redfish privilege registry for GET & HEAD
2969 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002970 /**
2971 * Functions triggers appropriate requests on DBus
2972 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002973 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002974 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002975 // This is incorrect, should be.
2976 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002977 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002978 .methods(boost::beast::http::verb::get)(
2979 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002980 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2981 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002982 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002983 {
2984 return;
2985 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002986 if (systemName != "system")
2987 {
2988 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2989 systemName);
2990 return;
2991 }
2992
Ed Tanous002d39b2022-05-31 08:59:27 -07002993 crow::connections::systemBus->async_method_call(
2994 [asyncResp](const boost::system::error_code ec,
2995 const std::vector<std::string>& resp) {
2996 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002997 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002998 if (ec.value() !=
2999 boost::system::errc::no_such_file_or_directory)
3000 {
3001 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3002 << ec.message();
3003 messages::internalError(asyncResp->res);
3004 return;
3005 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003006 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003007 asyncResp->res.jsonValue["@odata.type"] =
3008 "#LogEntryCollection.LogEntryCollection";
3009 asyncResp->res.jsonValue["@odata.id"] =
3010 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3011 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3012 asyncResp->res.jsonValue["Description"] =
3013 "Collection of Crashdump Entries";
3014 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3015 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003016
Ed Tanous002d39b2022-05-31 08:59:27 -07003017 for (const std::string& path : resp)
3018 {
3019 const sdbusplus::message::object_path objPath(path);
3020 // Get the log ID
3021 std::string logID = objPath.filename();
3022 if (logID.empty())
3023 {
3024 continue;
3025 }
3026 // Add the log entry to the array
3027 logCrashdumpEntry(asyncResp, logID,
3028 asyncResp->res.jsonValue["Members"]);
3029 }
3030 },
3031 "xyz.openbmc_project.ObjectMapper",
3032 "/xyz/openbmc_project/object_mapper",
3033 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
3034 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003035 });
3036}
Ed Tanous1da66f72018-07-27 16:13:37 -07003037
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003038inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003039{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003040 // Note: Deviated from redfish privilege registry for GET & HEAD
3041 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003042
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003043 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003044 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003045 // this is incorrect, should be
3046 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003047 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003048 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003049 [&app](const crow::Request& req,
3050 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003051 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003052 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003053 {
3054 return;
3055 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003056 if (systemName != "system")
3057 {
3058 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3059 systemName);
3060 ;
3061 return;
3062 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003063 const std::string& logID = param;
3064 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3065 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003066}
Ed Tanous1da66f72018-07-27 16:13:37 -07003067
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003068inline void requestRoutesCrashdumpFile(App& app)
3069{
3070 // Note: Deviated from redfish privilege registry for GET & HEAD
3071 // method for security reasons.
3072 BMCWEB_ROUTE(
3073 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003074 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003075 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003076 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003077 [](const crow::Request& req,
3078 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003079 const std::string& systemName, const std::string& logID,
3080 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003081 // Do not call getRedfishRoute here since the crashdump file is not a
3082 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003083
3084 if (systemName != "system")
3085 {
3086 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3087 systemName);
3088 ;
3089 return;
3090 }
3091
Ed Tanous002d39b2022-05-31 08:59:27 -07003092 auto getStoredLogCallback =
3093 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3094 const boost::system::error_code ec,
3095 const std::vector<
3096 std::pair<std::string, dbus::utility::DbusVariantType>>&
3097 resp) {
3098 if (ec)
3099 {
3100 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3101 messages::internalError(asyncResp->res);
3102 return;
3103 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003104
Ed Tanous002d39b2022-05-31 08:59:27 -07003105 std::string dbusFilename{};
3106 std::string dbusTimestamp{};
3107 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003108
Ed Tanous002d39b2022-05-31 08:59:27 -07003109 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3110 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003111
Ed Tanous002d39b2022-05-31 08:59:27 -07003112 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3113 dbusFilepath.empty())
3114 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003115 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003116 return;
3117 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003118
Ed Tanous002d39b2022-05-31 08:59:27 -07003119 // Verify the file name parameter is correct
3120 if (fileName != dbusFilename)
3121 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003122 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003123 return;
3124 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003125
Ed Tanous002d39b2022-05-31 08:59:27 -07003126 if (!std::filesystem::exists(dbusFilepath))
3127 {
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003128 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003129 return;
3130 }
3131 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3132 asyncResp->res.body() =
3133 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003134
Ed Tanous002d39b2022-05-31 08:59:27 -07003135 // Configure this to be a file download when accessed
3136 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003137 asyncResp->res.addHeader(
3138 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003139 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003140 sdbusplus::asio::getAllProperties(
3141 *crow::connections::systemBus, crashdumpObject,
3142 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3143 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003144 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003145}
3146
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003147enum class OEMDiagnosticType
3148{
3149 onDemand,
3150 telemetry,
3151 invalid,
3152};
3153
Ed Tanousf7725d72022-03-07 12:46:00 -08003154inline OEMDiagnosticType
3155 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003156{
3157 if (oemDiagStr == "OnDemand")
3158 {
3159 return OEMDiagnosticType::onDemand;
3160 }
3161 if (oemDiagStr == "Telemetry")
3162 {
3163 return OEMDiagnosticType::telemetry;
3164 }
3165
3166 return OEMDiagnosticType::invalid;
3167}
3168
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003169inline void requestRoutesCrashdumpCollect(App& app)
3170{
3171 // Note: Deviated from redfish privilege registry for GET & HEAD
3172 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003173 BMCWEB_ROUTE(
3174 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003175 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003176 // The below is incorrect; Should be ConfigureManager
3177 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003178 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003179 .methods(boost::beast::http::verb::post)(
3180 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003181 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3182 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003183 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003184 {
3185 return;
3186 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003187
3188 if (systemName != "system")
3189 {
3190 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3191 systemName);
3192 ;
3193 return;
3194 }
3195
Ed Tanous002d39b2022-05-31 08:59:27 -07003196 std::string diagnosticDataType;
3197 std::string oemDiagnosticDataType;
3198 if (!redfish::json_util::readJsonAction(
3199 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3200 "OEMDiagnosticDataType", oemDiagnosticDataType))
3201 {
3202 return;
3203 }
3204
3205 if (diagnosticDataType != "OEM")
3206 {
3207 BMCWEB_LOG_ERROR
3208 << "Only OEM DiagnosticDataType supported for Crashdump";
3209 messages::actionParameterValueFormatError(
3210 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3211 "CollectDiagnosticData");
3212 return;
3213 }
3214
3215 OEMDiagnosticType oemDiagType =
3216 getOEMDiagnosticType(oemDiagnosticDataType);
3217
3218 std::string iface;
3219 std::string method;
3220 std::string taskMatchStr;
3221 if (oemDiagType == OEMDiagnosticType::onDemand)
3222 {
3223 iface = crashdumpOnDemandInterface;
3224 method = "GenerateOnDemandLog";
3225 taskMatchStr = "type='signal',"
3226 "interface='org.freedesktop.DBus.Properties',"
3227 "member='PropertiesChanged',"
3228 "arg0namespace='com.intel.crashdump'";
3229 }
3230 else if (oemDiagType == OEMDiagnosticType::telemetry)
3231 {
3232 iface = crashdumpTelemetryInterface;
3233 method = "GenerateTelemetryLog";
3234 taskMatchStr = "type='signal',"
3235 "interface='org.freedesktop.DBus.Properties',"
3236 "member='PropertiesChanged',"
3237 "arg0namespace='com.intel.crashdump'";
3238 }
3239 else
3240 {
3241 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3242 << oemDiagnosticDataType;
3243 messages::actionParameterValueFormatError(
3244 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3245 "CollectDiagnosticData");
3246 return;
3247 }
3248
3249 auto collectCrashdumpCallback =
3250 [asyncResp, payload(task::Payload(req)),
3251 taskMatchStr](const boost::system::error_code ec,
3252 const std::string&) mutable {
3253 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003254 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003255 if (ec.value() == boost::system::errc::operation_not_supported)
3256 {
3257 messages::resourceInStandby(asyncResp->res);
3258 }
3259 else if (ec.value() ==
3260 boost::system::errc::device_or_resource_busy)
3261 {
3262 messages::serviceTemporarilyUnavailable(asyncResp->res,
3263 "60");
3264 }
3265 else
3266 {
3267 messages::internalError(asyncResp->res);
3268 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003269 return;
3270 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003271 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003272 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003273 const std::shared_ptr<task::TaskData>& taskData) {
3274 if (!err)
3275 {
3276 taskData->messages.emplace_back(messages::taskCompletedOK(
3277 std::to_string(taskData->index)));
3278 taskData->state = "Completed";
3279 }
3280 return task::completed;
3281 },
3282 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003283
Ed Tanous002d39b2022-05-31 08:59:27 -07003284 task->startTimer(std::chrono::minutes(5));
3285 task->populateResp(asyncResp->res);
3286 task->payload.emplace(std::move(payload));
3287 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003288
Ed Tanous002d39b2022-05-31 08:59:27 -07003289 crow::connections::systemBus->async_method_call(
3290 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3291 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003292 });
3293}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003294
Andrew Geisslercb92c032018-08-17 07:56:14 -07003295/**
3296 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3297 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003298inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003299{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003300 /**
3301 * Function handles POST method request.
3302 * The Clear Log actions does not require any parameter.The action deletes
3303 * all entries found in the Entries collection for this Log Service.
3304 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003305
George Liu0fda0f12021-11-16 10:06:17 +08003306 BMCWEB_ROUTE(
3307 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003308 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003309 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003310 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003311 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003312 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3313 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003314 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003315 {
3316 return;
3317 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003318 if (systemName != "system")
3319 {
3320 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3321 systemName);
3322 ;
3323 return;
3324 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003325 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003326
Ed Tanous002d39b2022-05-31 08:59:27 -07003327 // Process response from Logging service.
3328 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3329 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3330 if (ec)
3331 {
3332 // TODO Handle for specific error code
3333 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3334 asyncResp->res.result(
3335 boost::beast::http::status::internal_server_error);
3336 return;
3337 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003338
Ed Tanous002d39b2022-05-31 08:59:27 -07003339 asyncResp->res.result(boost::beast::http::status::no_content);
3340 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003341
Ed Tanous002d39b2022-05-31 08:59:27 -07003342 // Make call to Logging service to request Clear Log
3343 crow::connections::systemBus->async_method_call(
3344 respHandler, "xyz.openbmc_project.Logging",
3345 "/xyz/openbmc_project/logging",
3346 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3347 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003348}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003349
3350/****************************************************
3351 * Redfish PostCode interfaces
3352 * using DBUS interface: getPostCodesTS
3353 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003354inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003355{
Ed Tanous22d268c2022-05-19 09:39:07 -07003356 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003357 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003358 .methods(boost::beast::http::verb::get)(
3359 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003360 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3361 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003362 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003363 {
3364 return;
3365 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003366 if (systemName != "system")
3367 {
3368 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3369 systemName);
3370 ;
3371 return;
3372 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003373 asyncResp->res.jsonValue["@odata.id"] =
3374 "/redfish/v1/Systems/system/LogServices/PostCodes";
3375 asyncResp->res.jsonValue["@odata.type"] =
3376 "#LogService.v1_1_0.LogService";
3377 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3378 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3379 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3380 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3381 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3382 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303383
Ed Tanous002d39b2022-05-31 08:59:27 -07003384 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003385 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003386 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3387 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3388 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303389
Ed Tanous002d39b2022-05-31 08:59:27 -07003390 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3391 {"target",
3392 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003393 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003394}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003395
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003396inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003397{
George Liu0fda0f12021-11-16 10:06:17 +08003398 BMCWEB_ROUTE(
3399 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003400 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003401 // The following privilege is incorrect; It should be ConfigureManager
3402 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003403 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003404 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003405 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003406 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3407 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003408 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003409 {
3410 return;
3411 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003412 if (systemName != "system")
3413 {
3414 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3415 systemName);
3416 ;
3417 return;
3418 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003419 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003420
Ed Tanous002d39b2022-05-31 08:59:27 -07003421 // Make call to post-code service to request clear all
3422 crow::connections::systemBus->async_method_call(
3423 [asyncResp](const boost::system::error_code ec) {
3424 if (ec)
3425 {
3426 // TODO Handle for specific error code
3427 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3428 << ec;
3429 asyncResp->res.result(
3430 boost::beast::http::status::internal_server_error);
3431 messages::internalError(asyncResp->res);
3432 return;
3433 }
3434 },
3435 "xyz.openbmc_project.State.Boot.PostCode0",
3436 "/xyz/openbmc_project/State/Boot/PostCode0",
3437 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3438 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003439}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003440
3441static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003442 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303443 const boost::container::flat_map<
3444 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003445 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3446 const uint64_t skip = 0, const uint64_t top = 0)
3447{
3448 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003449 const registries::Message* message =
3450 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003451
3452 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003453 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003454
3455 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303456 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3457 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003458 {
3459 currentCodeIndex++;
3460 std::string postcodeEntryID =
3461 "B" + std::to_string(bootIndex) + "-" +
3462 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3463
3464 uint64_t usecSinceEpoch = code.first;
3465 uint64_t usTimeOffset = 0;
3466
3467 if (1 == currentCodeIndex)
3468 { // already incremented
3469 firstCodeTimeUs = code.first;
3470 }
3471 else
3472 {
3473 usTimeOffset = code.first - firstCodeTimeUs;
3474 }
3475
3476 // skip if no specific codeIndex is specified and currentCodeIndex does
3477 // not fall between top and skip
3478 if ((codeIndex == 0) &&
3479 (currentCodeIndex <= skip || currentCodeIndex > top))
3480 {
3481 continue;
3482 }
3483
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003484 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003485 // currentIndex
3486 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3487 {
3488 // This is done for simplicity. 1st entry is needed to calculate
3489 // time offset. To improve efficiency, one can get to the entry
3490 // directly (possibly with flatmap's nth method)
3491 continue;
3492 }
3493
3494 // currentCodeIndex is within top and skip or equal to specified code
3495 // index
3496
3497 // Get the Created time from the timestamp
3498 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003499 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003500 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003501
3502 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3503 std::ostringstream hexCode;
3504 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303505 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003506 std::ostringstream timeOffsetStr;
3507 // Set Fixed -Point Notation
3508 timeOffsetStr << std::fixed;
3509 // Set precision to 4 digits
3510 timeOffsetStr << std::setprecision(4);
3511 // Add double to stream
3512 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3513 std::vector<std::string> messageArgs = {
3514 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3515
3516 // Get MessageArgs template from message registry
3517 std::string msg;
3518 if (message != nullptr)
3519 {
3520 msg = message->message;
3521
3522 // fill in this post code value
3523 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003524 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003525 {
3526 std::string argStr = "%" + std::to_string(++i);
3527 size_t argPos = msg.find(argStr);
3528 if (argPos != std::string::npos)
3529 {
3530 msg.replace(argPos, argStr.length(), messageArg);
3531 }
3532 }
3533 }
3534
Tim Leed4342a92020-04-27 11:47:58 +08003535 // Get Severity template from message registry
3536 std::string severity;
3537 if (message != nullptr)
3538 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003539 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003540 }
3541
ZhikuiRena3316fc2020-01-29 14:58:08 -08003542 // add to AsyncResp
3543 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003544 nlohmann::json& bmcLogEntry = logEntryArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05003545 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003546 bmcLogEntry["@odata.id"] =
3547 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3548 postcodeEntryID;
3549 bmcLogEntry["Name"] = "POST Code Log Entry";
3550 bmcLogEntry["Id"] = postcodeEntryID;
3551 bmcLogEntry["Message"] = std::move(msg);
3552 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3553 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3554 bmcLogEntry["EntryType"] = "Event";
3555 bmcLogEntry["Severity"] = std::move(severity);
3556 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003557 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3558 {
3559 bmcLogEntry["AdditionalDataURI"] =
3560 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3561 postcodeEntryID + "/attachment";
3562 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003563 }
3564}
3565
zhanghch058d1b46d2021-04-01 11:18:24 +08003566static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003567 const uint16_t bootIndex,
3568 const uint64_t codeIndex)
3569{
3570 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303571 [aResp, bootIndex,
3572 codeIndex](const boost::system::error_code ec,
3573 const boost::container::flat_map<
3574 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3575 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003576 if (ec)
3577 {
3578 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3579 messages::internalError(aResp->res);
3580 return;
3581 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003582
Ed Tanous002d39b2022-05-31 08:59:27 -07003583 // skip the empty postcode boots
3584 if (postcode.empty())
3585 {
3586 return;
3587 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003588
Ed Tanous002d39b2022-05-31 08:59:27 -07003589 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003590
Ed Tanous002d39b2022-05-31 08:59:27 -07003591 aResp->res.jsonValue["Members@odata.count"] =
3592 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003593 },
Jonathan Doman15124762021-01-07 17:54:17 -08003594 "xyz.openbmc_project.State.Boot.PostCode0",
3595 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003596 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3597 bootIndex);
3598}
3599
zhanghch058d1b46d2021-04-01 11:18:24 +08003600static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003601 const uint16_t bootIndex,
3602 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003603 const uint64_t entryCount, size_t skip,
3604 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003605{
3606 crow::connections::systemBus->async_method_call(
3607 [aResp, bootIndex, bootCount, entryCount, skip,
3608 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303609 const boost::container::flat_map<
3610 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3611 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003612 if (ec)
3613 {
3614 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3615 messages::internalError(aResp->res);
3616 return;
3617 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003618
Ed Tanous002d39b2022-05-31 08:59:27 -07003619 uint64_t endCount = entryCount;
3620 if (!postcode.empty())
3621 {
3622 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003623 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003624 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003625 uint64_t thisBootSkip =
3626 std::max(static_cast<uint64_t>(skip), entryCount) -
3627 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003628 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003629 std::min(static_cast<uint64_t>(top + skip), endCount) -
3630 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003631
3632 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3633 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003634 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003635 aResp->res.jsonValue["Members@odata.count"] = endCount;
3636 }
3637
3638 // continue to previous bootIndex
3639 if (bootIndex < bootCount)
3640 {
3641 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3642 bootCount, endCount, skip, top);
3643 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003644 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003645 {
3646 aResp->res.jsonValue["Members@odata.nextLink"] =
3647 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3648 std::to_string(skip + top);
3649 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003650 },
Jonathan Doman15124762021-01-07 17:54:17 -08003651 "xyz.openbmc_project.State.Boot.PostCode0",
3652 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003653 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3654 bootIndex);
3655}
3656
zhanghch058d1b46d2021-04-01 11:18:24 +08003657static void
3658 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003659 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003660{
3661 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003662 sdbusplus::asio::getProperty<uint16_t>(
3663 *crow::connections::systemBus,
3664 "xyz.openbmc_project.State.Boot.PostCode0",
3665 "/xyz/openbmc_project/State/Boot/PostCode0",
3666 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3667 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3668 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003669 if (ec)
3670 {
3671 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3672 messages::internalError(aResp->res);
3673 return;
3674 }
3675 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003676 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003677}
3678
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003679inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003680{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003681 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003682 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003683 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003684 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003685 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003686 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3687 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003688 query_param::QueryCapabilities capabilities = {
3689 .canDelegateTop = true,
3690 .canDelegateSkip = true,
3691 };
3692 query_param::Query delegatedQuery;
3693 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003694 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003695 {
3696 return;
3697 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003698
3699 if (systemName != "system")
3700 {
3701 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3702 systemName);
3703 ;
3704 return;
3705 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003706 asyncResp->res.jsonValue["@odata.type"] =
3707 "#LogEntryCollection.LogEntryCollection";
3708 asyncResp->res.jsonValue["@odata.id"] =
3709 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3710 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3711 asyncResp->res.jsonValue["Description"] =
3712 "Collection of POST Code Log Entries";
3713 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3714 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003715 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003716 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003717 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003718 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003719}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003720
George Liu647b3cd2021-07-05 12:43:56 +08003721/**
3722 * @brief Parse post code ID and get the current value and index value
3723 * eg: postCodeID=B1-2, currentValue=1, index=2
3724 *
3725 * @param[in] postCodeID Post Code ID
3726 * @param[out] currentValue Current value
3727 * @param[out] index Index value
3728 *
3729 * @return bool true if the parsing is successful, false the parsing fails
3730 */
3731inline static bool parsePostCode(const std::string& postCodeID,
3732 uint64_t& currentValue, uint16_t& index)
3733{
3734 std::vector<std::string> split;
3735 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3736 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3737 {
3738 return false;
3739 }
3740
Ed Tanousca45aa32022-01-07 09:28:45 -08003741 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003742 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003743 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003744 const char* end = split[0].data() + split[0].size();
3745 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3746
3747 if (ptrIndex != end || ecIndex != std::errc())
3748 {
3749 return false;
3750 }
3751
3752 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003753
3754 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003755 end = split[1].data() + split[1].size();
3756 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003757
Tony Lee517d9a52022-06-28 15:41:23 +08003758 return ptrValue == end && ecValue == std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003759}
3760
3761inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3762{
George Liu0fda0f12021-11-16 10:06:17 +08003763 BMCWEB_ROUTE(
3764 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003765 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003766 .privileges(redfish::privileges::getLogEntry)
3767 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003768 [&app](const crow::Request& req,
3769 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003770 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003771 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003772 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003773 {
3774 return;
3775 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003776 if (http_helpers::isContentTypeAllowed(
3777 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003778 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003779 {
3780 asyncResp->res.result(boost::beast::http::status::bad_request);
3781 return;
3782 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003783 if (systemName != "system")
3784 {
3785 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3786 systemName);
3787 ;
3788 return;
3789 }
George Liu647b3cd2021-07-05 12:43:56 +08003790
Ed Tanous002d39b2022-05-31 08:59:27 -07003791 uint64_t currentValue = 0;
3792 uint16_t index = 0;
3793 if (!parsePostCode(postCodeID, currentValue, index))
3794 {
3795 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3796 return;
3797 }
George Liu647b3cd2021-07-05 12:43:56 +08003798
Ed Tanous002d39b2022-05-31 08:59:27 -07003799 crow::connections::systemBus->async_method_call(
3800 [asyncResp, postCodeID, currentValue](
3801 const boost::system::error_code ec,
3802 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3803 postcodes) {
3804 if (ec.value() == EBADR)
3805 {
3806 messages::resourceNotFound(asyncResp->res, "LogEntry",
3807 postCodeID);
3808 return;
3809 }
3810 if (ec)
3811 {
3812 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3813 messages::internalError(asyncResp->res);
3814 return;
3815 }
George Liu647b3cd2021-07-05 12:43:56 +08003816
Ed Tanous002d39b2022-05-31 08:59:27 -07003817 size_t value = static_cast<size_t>(currentValue) - 1;
3818 if (value == std::string::npos || postcodes.size() < currentValue)
3819 {
3820 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3821 messages::resourceNotFound(asyncResp->res, "LogEntry",
3822 postCodeID);
3823 return;
3824 }
George Liu647b3cd2021-07-05 12:43:56 +08003825
Ed Tanous002d39b2022-05-31 08:59:27 -07003826 const auto& [tID, c] = postcodes[value];
3827 if (c.empty())
3828 {
3829 BMCWEB_LOG_INFO << "No found post code data";
3830 messages::resourceNotFound(asyncResp->res, "LogEntry",
3831 postCodeID);
3832 return;
3833 }
3834 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3835 const char* d = reinterpret_cast<const char*>(c.data());
3836 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003837
Ed Tanousd9f6c622022-03-17 09:12:17 -07003838 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07003839 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07003840 asyncResp->res.addHeader(
3841 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07003842 asyncResp->res.body() = crow::utility::base64encode(strData);
3843 },
3844 "xyz.openbmc_project.State.Boot.PostCode0",
3845 "/xyz/openbmc_project/State/Boot/PostCode0",
3846 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3847 });
George Liu647b3cd2021-07-05 12:43:56 +08003848}
3849
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003850inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003851{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003852 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003853 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003854 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003855 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003856 [&app](const crow::Request& req,
3857 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003858 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003859 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003860 {
3861 return;
3862 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003863 if (systemName != "system")
3864 {
3865 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3866 systemName);
3867 return;
3868 }
3869
Ed Tanous002d39b2022-05-31 08:59:27 -07003870 uint16_t bootIndex = 0;
3871 uint64_t codeIndex = 0;
3872 if (!parsePostCode(targetID, codeIndex, bootIndex))
3873 {
3874 // Requested ID was not found
Jiaqing Zhao9db4ba22022-10-09 17:24:40 +08003875 messages::resourceNotFound(asyncResp->res, "LogEntry", targetID);
Ed Tanous002d39b2022-05-31 08:59:27 -07003876 return;
3877 }
3878 if (bootIndex == 0 || codeIndex == 0)
3879 {
3880 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3881 << targetID;
3882 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003883
Vijay Lobo9c11a172021-10-07 16:53:16 -05003884 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07003885 asyncResp->res.jsonValue["@odata.id"] =
3886 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3887 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3888 asyncResp->res.jsonValue["Description"] =
3889 "Collection of POST Code Log Entries";
3890 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3891 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003892
Ed Tanous002d39b2022-05-31 08:59:27 -07003893 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3894 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003895}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003896
Ed Tanous1da66f72018-07-27 16:13:37 -07003897} // namespace redfish