blob: ecd5d59684618d0aff067ca8498820c50bf9c05f [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 {
Ed Tanousace85d62021-10-26 12:45:59 -0700293 messages::resourceMissingAtURI(
294 asyncResp->res, crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700295 return false;
296 }
297 }
298 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700299 auto [ptr, ec] =
300 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
301 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700302 {
Ed Tanousace85d62021-10-26 12:45:59 -0700303 messages::resourceMissingAtURI(asyncResp->res,
304 crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700305 return false;
306 }
307 return true;
308}
309
Jason M. Bills95820182019-04-22 16:25:34 -0700310static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500311 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700312{
313 static const std::filesystem::path redfishLogDir = "/var/log";
314 static const std::string redfishLogFilename = "redfish";
315
316 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500317 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700318 std::filesystem::directory_iterator(redfishLogDir))
319 {
320 // If we find a redfish log file, save the path
321 std::string filename = dirEnt.path().filename();
Ed Tanous11ba3972022-07-11 09:50:41 -0700322 if (filename.starts_with(redfishLogFilename))
Jason M. Bills95820182019-04-22 16:25:34 -0700323 {
324 redfishLogFiles.emplace_back(redfishLogDir / filename);
325 }
326 }
327 // As the log files rotate, they are appended with a ".#" that is higher for
328 // the older logs. Since we don't expect more than 10 log files, we
329 // can just sort the list to get them in order from newest to oldest
330 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
331
332 return !redfishLogFiles.empty();
333}
334
Claire Weinanaefe3782022-07-15 19:17:19 -0700335inline void parseDumpEntryFromDbusObject(
Jiaqing Zhao2d613eb2022-08-15 16:03:00 +0800336 const dbus::utility::ManagedObjectType::value_type& object,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700337 std::string& dumpStatus, uint64_t& size, uint64_t& timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700338 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
339{
340 for (const auto& interfaceMap : object.second)
341 {
342 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
343 {
344 for (const auto& propertyMap : interfaceMap.second)
345 {
346 if (propertyMap.first == "Status")
347 {
348 const auto* status =
349 std::get_if<std::string>(&propertyMap.second);
350 if (status == nullptr)
351 {
352 messages::internalError(asyncResp->res);
353 break;
354 }
355 dumpStatus = *status;
356 }
357 }
358 }
359 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
360 {
361 for (const auto& propertyMap : interfaceMap.second)
362 {
363 if (propertyMap.first == "Size")
364 {
365 const auto* sizePtr =
366 std::get_if<uint64_t>(&propertyMap.second);
367 if (sizePtr == nullptr)
368 {
369 messages::internalError(asyncResp->res);
370 break;
371 }
372 size = *sizePtr;
373 break;
374 }
375 }
376 }
377 else if (interfaceMap.first == "xyz.openbmc_project.Time.EpochTime")
378 {
379 for (const auto& propertyMap : interfaceMap.second)
380 {
381 if (propertyMap.first == "Elapsed")
382 {
383 const uint64_t* usecsTimeStamp =
384 std::get_if<uint64_t>(&propertyMap.second);
385 if (usecsTimeStamp == nullptr)
386 {
387 messages::internalError(asyncResp->res);
388 break;
389 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700390 timestampUs = *usecsTimeStamp;
Claire Weinanaefe3782022-07-15 19:17:19 -0700391 break;
392 }
393 }
394 }
395 }
396}
397
Nan Zhou21ab4042022-06-26 23:07:40 +0000398static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800399{
400 std::string entriesPath;
401
402 if (dumpType == "BMC")
403 {
404 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
405 }
406 else if (dumpType == "FaultLog")
407 {
408 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
409 }
410 else if (dumpType == "System")
411 {
412 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
413 }
414 else
415 {
416 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
417 << dumpType;
418 }
419
420 // Returns empty string on error
421 return entriesPath;
422}
423
zhanghch058d1b46d2021-04-01 11:18:24 +0800424inline void
425 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
426 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500427{
Claire Weinanfdd26902022-03-01 14:18:25 -0800428 std::string entriesPath = getDumpEntriesPath(dumpType);
429 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500430 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500431 messages::internalError(asyncResp->res);
432 return;
433 }
434
435 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800436 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800437 dumpType](const boost::system::error_code ec,
438 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 if (ec)
440 {
441 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
442 messages::internalError(asyncResp->res);
443 return;
444 }
445
Claire Weinanfdd26902022-03-01 14:18:25 -0800446 // Remove ending slash
447 std::string odataIdStr = entriesPath;
448 if (!odataIdStr.empty())
449 {
450 odataIdStr.pop_back();
451 }
452
453 asyncResp->res.jsonValue["@odata.type"] =
454 "#LogEntryCollection.LogEntryCollection";
455 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
456 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
457 asyncResp->res.jsonValue["Description"] =
458 "Collection of " + dumpType + " Dump Entries";
459
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
461 entriesArray = nlohmann::json::array();
462 std::string dumpEntryPath =
463 "/xyz/openbmc_project/dump/" +
464 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
465
466 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
467 return AlphanumLess<std::string>()(l.first.filename(),
468 r.first.filename());
469 });
470
471 for (auto& object : resp)
472 {
473 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500474 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700475 continue;
476 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700477 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 uint64_t size = 0;
479 std::string dumpStatus;
Jason M. Bills433b68b2022-06-28 12:24:26 -0700480 nlohmann::json::object_t thisEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -0700481
482 std::string entryID = object.first.filename();
483 if (entryID.empty())
484 {
485 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500486 }
487
Claire Weinanc6fecda2022-07-15 10:43:25 -0700488 parseDumpEntryFromDbusObject(object, dumpStatus, size, timestampUs,
Claire Weinanaefe3782022-07-15 19:17:19 -0700489 asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700490
491 if (dumpStatus !=
492 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
493 !dumpStatus.empty())
494 {
495 // Dump status is not Complete, no need to enumerate
496 continue;
497 }
498
Vijay Lobo9c11a172021-10-07 16:53:16 -0500499 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800500 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 thisEntry["Id"] = entryID;
502 thisEntry["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 thisEntry["Name"] = dumpType + " Dump Entry";
504
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 if (dumpType == "BMC")
506 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700507 thisEntry["Created"] = redfish::time_utils::getDateTimeUint(
508 timestampUs / 1000 / 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700509 thisEntry["DiagnosticDataType"] = "Manager";
510 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800511 entriesPath + entryID + "/attachment";
512 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700513 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700514 else if (dumpType == "FaultLog")
515 {
516 thisEntry["Created"] =
517 redfish::time_utils::getDateTimeUintUs(timestampUs);
518 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700519 else if (dumpType == "System")
520 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700521 thisEntry["Created"] = redfish::time_utils::getDateTimeUint(
522 timestampUs / 1000 / 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700523 thisEntry["DiagnosticDataType"] = "OEM";
524 thisEntry["OEMDiagnosticDataType"] = "System";
525 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800526 entriesPath + entryID + "/attachment";
527 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 }
529 entriesArray.push_back(std::move(thisEntry));
530 }
531 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500532 },
533 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
534 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
535}
536
zhanghch058d1b46d2021-04-01 11:18:24 +0800537inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700538 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800539 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500540{
Claire Weinanfdd26902022-03-01 14:18:25 -0800541 std::string entriesPath = getDumpEntriesPath(dumpType);
542 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500543 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500544 messages::internalError(asyncResp->res);
545 return;
546 }
547
548 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800549 [asyncResp, entryID, dumpType,
550 entriesPath](const boost::system::error_code ec,
Ed Tanous02cad962022-06-30 16:50:15 -0700551 const dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700552 if (ec)
553 {
554 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
555 messages::internalError(asyncResp->res);
556 return;
557 }
558
559 bool foundDumpEntry = false;
560 std::string dumpEntryPath =
561 "/xyz/openbmc_project/dump/" +
562 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
563
564 for (const auto& objectPath : resp)
565 {
566 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500567 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700568 continue;
569 }
570
571 foundDumpEntry = true;
Claire Weinanc6fecda2022-07-15 10:43:25 -0700572 uint64_t timestampUs = 0;
Ed Tanous002d39b2022-05-31 08:59:27 -0700573 uint64_t size = 0;
574 std::string dumpStatus;
575
Claire Weinanaefe3782022-07-15 19:17:19 -0700576 parseDumpEntryFromDbusObject(objectPath, dumpStatus, size,
Claire Weinanc6fecda2022-07-15 10:43:25 -0700577 timestampUs, asyncResp);
Ed Tanous002d39b2022-05-31 08:59:27 -0700578
579 if (dumpStatus !=
580 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
581 !dumpStatus.empty())
582 {
583 // Dump status is not Complete
584 // return not found until status is changed to Completed
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200585 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
586 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500587 return;
588 }
589
Ed Tanous002d39b2022-05-31 08:59:27 -0700590 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -0500591 "#LogEntry.v1_9_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800592 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700593 asyncResp->res.jsonValue["Id"] = entryID;
594 asyncResp->res.jsonValue["EntryType"] = "Event";
Ed Tanous002d39b2022-05-31 08:59:27 -0700595 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500596
Ed Tanous002d39b2022-05-31 08:59:27 -0700597 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500598 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700599 asyncResp->res.jsonValue["Created"] =
600 redfish::time_utils::getDateTimeUint(timestampUs / 1000 /
601 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700602 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
603 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800604 entriesPath + entryID + "/attachment";
605 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500606 }
Claire Weinanc6fecda2022-07-15 10:43:25 -0700607 else if (dumpType == "FaultLog")
608 {
609 asyncResp->res.jsonValue["Created"] =
610 redfish::time_utils::getDateTimeUintUs(timestampUs);
611 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700612 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500613 {
Claire Weinanc6fecda2022-07-15 10:43:25 -0700614 asyncResp->res.jsonValue["Created"] =
615 redfish::time_utils::getDateTimeUint(timestampUs / 1000 /
616 1000);
Ed Tanous002d39b2022-05-31 08:59:27 -0700617 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
618 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
619 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800620 entriesPath + entryID + "/attachment";
621 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500622 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700623 }
624 if (!foundDumpEntry)
625 {
626 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
627 messages::internalError(asyncResp->res);
628 return;
629 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500630 },
631 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
632 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
633}
634
zhanghch058d1b46d2021-04-01 11:18:24 +0800635inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800636 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500637 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500638{
Ed Tanous002d39b2022-05-31 08:59:27 -0700639 auto respHandler =
640 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500641 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
642 if (ec)
643 {
George Liu3de8d8b2021-03-22 17:49:39 +0800644 if (ec.value() == EBADR)
645 {
646 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
647 return;
648 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500649 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800650 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500651 messages::internalError(asyncResp->res);
652 return;
653 }
654 };
655 crow::connections::systemBus->async_method_call(
656 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500657 "/xyz/openbmc_project/dump/" +
658 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
659 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500660 "xyz.openbmc_project.Object.Delete", "Delete");
661}
662
zhanghch058d1b46d2021-04-01 11:18:24 +0800663inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700664 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800665 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
666 const uint32_t& dumpId, const std::string& dumpPath,
667 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500668{
669 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -0500670 [dumpId, dumpPath,
671 dumpType](boost::system::error_code err, sdbusplus::message_t& m,
672 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700673 if (err)
674 {
675 BMCWEB_LOG_ERROR << "Error in creating a dump";
676 taskData->state = "Cancelled";
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500677 return task::completed;
Ed Tanous002d39b2022-05-31 08:59:27 -0700678 }
679
680 dbus::utility::DBusInteracesMap interfacesList;
681
682 sdbusplus::message::object_path objPath;
683
684 m.read(objPath, interfacesList);
685
686 if (objPath.str ==
687 "/xyz/openbmc_project/dump/" +
688 std::string(boost::algorithm::to_lower_copy(dumpType)) +
689 "/entry/" + std::to_string(dumpId))
690 {
691 nlohmann::json retMessage = messages::success();
692 taskData->messages.emplace_back(retMessage);
693
694 std::string headerLoc =
695 "Location: " + dumpPath + std::to_string(dumpId);
696 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
697
698 taskData->state = "Completed";
699 return task::completed;
700 }
701 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500702 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800703 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500704 "member='InterfacesAdded', "
705 "path='/xyz/openbmc_project/dump'");
706
707 task->startTimer(std::chrono::minutes(3));
708 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700709 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500710}
711
zhanghch058d1b46d2021-04-01 11:18:24 +0800712inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
713 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500714{
Claire Weinanfdd26902022-03-01 14:18:25 -0800715 std::string dumpPath = getDumpEntriesPath(dumpType);
716 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500717 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500718 messages::internalError(asyncResp->res);
719 return;
720 }
721
722 std::optional<std::string> diagnosticDataType;
723 std::optional<std::string> oemDiagnosticDataType;
724
Willy Tu15ed6782021-12-14 11:03:16 -0800725 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500726 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
727 "OEMDiagnosticDataType", oemDiagnosticDataType))
728 {
729 return;
730 }
731
732 if (dumpType == "System")
733 {
734 if (!oemDiagnosticDataType || !diagnosticDataType)
735 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800736 BMCWEB_LOG_ERROR
737 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500738 messages::actionParameterMissing(
739 asyncResp->res, "CollectDiagnosticData",
740 "DiagnosticDataType & OEMDiagnosticDataType");
741 return;
742 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700743 if ((*oemDiagnosticDataType != "System") ||
744 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500745 {
746 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700747 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500748 return;
749 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500750 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500751 }
752 else if (dumpType == "BMC")
753 {
754 if (!diagnosticDataType)
755 {
George Liu0fda0f12021-11-16 10:06:17 +0800756 BMCWEB_LOG_ERROR
757 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500758 messages::actionParameterMissing(
759 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
760 return;
761 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700762 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500763 {
764 BMCWEB_LOG_ERROR
765 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700766 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500767 return;
768 }
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500769 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/";
770 }
771 else
772 {
773 BMCWEB_LOG_ERROR << "CreateDump failed. Unknown dump type";
774 messages::internalError(asyncResp->res);
775 return;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500776 }
777
778 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700779 [asyncResp, payload(task::Payload(req)), dumpPath,
780 dumpType](const boost::system::error_code ec,
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500781 const sdbusplus::message::message& msg,
Ed Tanous98be3e32021-09-16 15:05:36 -0700782 const uint32_t& dumpId) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700783 if (ec)
784 {
785 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
Asmitha Karunanithi59075712021-10-22 01:17:41 -0500786 const sd_bus_error* dbusError = msg.get_error();
787 if (dbusError == nullptr)
788 {
789 messages::internalError(asyncResp->res);
790 return;
791 }
792
793 BMCWEB_LOG_ERROR << "CreateDump DBus error: " << dbusError->name
794 << " and error msg: " << dbusError->message;
795 if (std::string_view(
796 "xyz.openbmc_project.Common.Error.NotAllowed") ==
797 dbusError->name)
798 {
799 messages::resourceInStandby(asyncResp->res);
800 return;
801 }
802 if (std::string_view(
803 "xyz.openbmc_project.Dump.Create.Error.Disabled") ==
804 dbusError->name)
805 {
806 messages::serviceDisabled(asyncResp->res, dumpPath);
807 return;
808 }
809 if (std::string_view(
810 "xyz.openbmc_project.Common.Error.Unavailable") ==
811 dbusError->name)
812 {
813 messages::resourceInUse(asyncResp->res);
814 return;
815 }
816 // Other Dbus errors such as:
817 // xyz.openbmc_project.Common.Error.InvalidArgument &
818 // org.freedesktop.DBus.Error.InvalidArgs are all related to
819 // the dbus call that is made here in the bmcweb
820 // implementation and has nothing to do with the client's
821 // input in the request. Hence, returning internal error
822 // back to the client.
Ed Tanous002d39b2022-05-31 08:59:27 -0700823 messages::internalError(asyncResp->res);
824 return;
825 }
826 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500827
Ed Tanous002d39b2022-05-31 08:59:27 -0700828 createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
829 dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500830 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500831 "xyz.openbmc_project.Dump.Manager",
832 "/xyz/openbmc_project/dump/" +
833 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500834 "xyz.openbmc_project.Dump.Create", "CreateDump");
835}
836
zhanghch058d1b46d2021-04-01 11:18:24 +0800837inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
838 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500839{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500840 std::string dumpTypeLowerCopy =
841 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800842
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500843 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800844 [asyncResp, dumpType](
845 const boost::system::error_code ec,
846 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700847 if (ec)
848 {
849 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
850 messages::internalError(asyncResp->res);
851 return;
852 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500853
Ed Tanous002d39b2022-05-31 08:59:27 -0700854 for (const std::string& path : subTreePaths)
855 {
856 sdbusplus::message::object_path objPath(path);
857 std::string logID = objPath.filename();
858 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500859 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700860 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500861 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700862 deleteDumpEntry(asyncResp, logID, dumpType);
863 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500864 },
865 "xyz.openbmc_project.ObjectMapper",
866 "/xyz/openbmc_project/object_mapper",
867 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500868 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
869 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
870 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500871}
872
Ed Tanousb9d36b42022-02-26 21:42:46 -0800873inline static void
874 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
875 std::string& filename, std::string& timestamp,
876 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700877{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200878 const std::string* filenamePtr = nullptr;
879 const std::string* timestampPtr = nullptr;
880 const std::string* logfilePtr = nullptr;
881
882 const bool success = sdbusplus::unpackPropertiesNoThrow(
883 dbus_utils::UnpackErrorPrinter(), params, "Timestamp", timestampPtr,
884 "Filename", filenamePtr, "Log", logfilePtr);
885
886 if (!success)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700887 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200888 return;
889 }
890
891 if (filenamePtr != nullptr)
892 {
893 filename = *filenamePtr;
894 }
895
896 if (timestampPtr != nullptr)
897 {
898 timestamp = *timestampPtr;
899 }
900
901 if (logfilePtr != nullptr)
902 {
903 logfile = *logfilePtr;
Johnathan Mantey043a0532020-03-10 17:15:28 -0700904 }
905}
906
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500907constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700908inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700909{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800910 /**
911 * Functions triggers appropriate requests on DBus
912 */
Ed Tanous22d268c2022-05-19 09:39:07 -0700913 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700914 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700915 .methods(boost::beast::http::verb::get)(
916 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -0700917 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
918 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000919 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 {
921 return;
922 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700923 if (systemName != "system")
924 {
925 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
926 systemName);
927 return;
928 }
929
Ed Tanous002d39b2022-05-31 08:59:27 -0700930 // Collections don't include the static data added by SubRoute
931 // because it has a duplicate entry for members
932 asyncResp->res.jsonValue["@odata.type"] =
933 "#LogServiceCollection.LogServiceCollection";
934 asyncResp->res.jsonValue["@odata.id"] =
935 "/redfish/v1/Systems/system/LogServices";
936 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
937 asyncResp->res.jsonValue["Description"] =
938 "Collection of LogServices for this Computer System";
939 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
940 logServiceArray = nlohmann::json::array();
941 nlohmann::json::object_t eventLog;
942 eventLog["@odata.id"] =
943 "/redfish/v1/Systems/system/LogServices/EventLog";
944 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500945#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700946 nlohmann::json::object_t dumpLog;
947 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
948 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -0600949#endif
950
Jason M. Billsd53dd412019-02-12 17:16:22 -0800951#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700952 nlohmann::json::object_t crashdump;
953 crashdump["@odata.id"] =
954 "/redfish/v1/Systems/system/LogServices/Crashdump";
955 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -0800956#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800957
958#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -0700959 nlohmann::json::object_t hostlogger;
960 hostlogger["@odata.id"] =
961 "/redfish/v1/Systems/system/LogServices/HostLogger";
962 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +0800963#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700964 asyncResp->res.jsonValue["Members@odata.count"] =
965 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800966
Ed Tanous002d39b2022-05-31 08:59:27 -0700967 crow::connections::systemBus->async_method_call(
968 [asyncResp](const boost::system::error_code ec,
969 const dbus::utility::MapperGetSubTreePathsResponse&
970 subtreePath) {
971 if (ec)
972 {
973 BMCWEB_LOG_ERROR << ec;
974 return;
975 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700976
Ed Tanous002d39b2022-05-31 08:59:27 -0700977 for (const auto& pathStr : subtreePath)
978 {
979 if (pathStr.find("PostCode") != std::string::npos)
980 {
981 nlohmann::json& logServiceArrayLocal =
982 asyncResp->res.jsonValue["Members"];
Ed Tanous613dabe2022-07-09 11:17:36 -0700983 nlohmann::json::object_t member;
984 member["@odata.id"] =
985 "/redfish/v1/Systems/system/LogServices/PostCodes";
986
987 logServiceArrayLocal.push_back(std::move(member));
988
Ed Tanous002d39b2022-05-31 08:59:27 -0700989 asyncResp->res.jsonValue["Members@odata.count"] =
990 logServiceArrayLocal.size();
991 return;
992 }
993 }
994 },
995 "xyz.openbmc_project.ObjectMapper",
996 "/xyz/openbmc_project/object_mapper",
997 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
998 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -0700999 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001000}
1001
1002inline void requestRoutesEventLogService(App& app)
1003{
Ed Tanous22d268c2022-05-19 09:39:07 -07001004 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -07001005 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07001006 .methods(boost::beast::http::verb::get)(
1007 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001008 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1009 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001010 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001011 {
1012 return;
1013 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001014 if (systemName != "system")
1015 {
1016 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1017 systemName);
1018 return;
1019 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001020 asyncResp->res.jsonValue["@odata.id"] =
1021 "/redfish/v1/Systems/system/LogServices/EventLog";
1022 asyncResp->res.jsonValue["@odata.type"] =
1023 "#LogService.v1_1_0.LogService";
1024 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1025 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
1026 asyncResp->res.jsonValue["Id"] = "EventLog";
1027 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05301028
Ed Tanous002d39b2022-05-31 08:59:27 -07001029 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07001030 redfish::time_utils::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +05301031
Ed Tanous002d39b2022-05-31 08:59:27 -07001032 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
1033 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1034 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05301035
Ed Tanous002d39b2022-05-31 08:59:27 -07001036 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1037 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1038 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001039
Ed Tanous002d39b2022-05-31 08:59:27 -07001040 {"target",
1041 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001042 });
1043}
1044
1045inline void requestRoutesJournalEventLogClear(App& app)
1046{
Jason M. Bills4978b632022-02-22 14:17:43 -08001047 BMCWEB_ROUTE(
1048 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001049 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001050 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001051 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001052 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001053 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1054 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001055 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001056 {
1057 return;
1058 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001059 if (systemName != "system")
1060 {
1061 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1062 systemName);
1063 return;
1064 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001065 // Clear the EventLog by deleting the log files
1066 std::vector<std::filesystem::path> redfishLogFiles;
1067 if (getRedfishLogFiles(redfishLogFiles))
1068 {
1069 for (const std::filesystem::path& file : redfishLogFiles)
1070 {
1071 std::error_code ec;
1072 std::filesystem::remove(file, ec);
1073 }
1074 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001075
Ed Tanous002d39b2022-05-31 08:59:27 -07001076 // Reload rsyslog so it knows to start new log files
1077 crow::connections::systemBus->async_method_call(
1078 [asyncResp](const boost::system::error_code ec) {
1079 if (ec)
1080 {
1081 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1082 messages::internalError(asyncResp->res);
1083 return;
1084 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001085
Ed Tanous002d39b2022-05-31 08:59:27 -07001086 messages::success(asyncResp->res);
1087 },
1088 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1089 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1090 "replace");
1091 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001092}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001093
Jason M. Billsac992cd2022-06-24 13:31:46 -07001094enum class LogParseError
1095{
1096 success,
1097 parseFailed,
1098 messageIdNotInRegistry,
1099};
1100
1101static LogParseError
1102 fillEventLogEntryJson(const std::string& logEntryID,
1103 const std::string& logEntry,
1104 nlohmann::json::object_t& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001105{
Jason M. Bills95820182019-04-22 16:25:34 -07001106 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001107 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001108 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001109 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001110 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001111 return LogParseError::parseFailed;
Jason M. Bills95820182019-04-22 16:25:34 -07001112 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001113 std::string timestamp = logEntry.substr(0, space);
1114 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001115 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001116 if (entryStart == std::string::npos)
1117 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001118 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001119 }
1120 std::string_view entry(logEntry);
1121 entry.remove_prefix(entryStart);
1122 // Use split to separate the entry into its fields
1123 std::vector<std::string> logEntryFields;
1124 boost::split(logEntryFields, entry, boost::is_any_of(","),
1125 boost::token_compress_on);
1126 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001127 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001128 {
Jason M. Billsac992cd2022-06-24 13:31:46 -07001129 return LogParseError::parseFailed;
Jason M. Billscd225da2019-05-08 15:31:57 -07001130 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001131 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001132
Jason M. Bills4851d452019-03-28 11:27:48 -07001133 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001134 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001135
Sui Chen54417b02022-03-24 14:59:52 -07001136 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001137 {
Sui Chen54417b02022-03-24 14:59:52 -07001138 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001139 return LogParseError::messageIdNotInRegistry;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001140 }
1141
Sui Chen54417b02022-03-24 14:59:52 -07001142 std::string msg = message->message;
1143
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001144 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001145 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001146 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001147 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001148 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001149 // If the first string is empty, assume there are no MessageArgs
1150 std::size_t messageArgsSize = 0;
1151 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001152 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001153 messageArgsSize = logEntryFields.size() - 1;
1154 }
1155
Ed Tanous23a21a12020-07-25 04:45:05 +00001156 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001157
1158 // Fill the MessageArgs into the Message
1159 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001160 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001161 {
1162 std::string argStr = "%" + std::to_string(++i);
1163 size_t argPos = msg.find(argStr);
1164 if (argPos != std::string::npos)
1165 {
1166 msg.replace(argPos, argStr.length(), messageArg);
1167 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001168 }
1169 }
1170
Jason M. Bills95820182019-04-22 16:25:34 -07001171 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1172 // format which matches the Redfish format except for the fractional seconds
1173 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001174 std::size_t dot = timestamp.find_first_of('.');
1175 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001176 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001177 {
Jason M. Bills95820182019-04-22 16:25:34 -07001178 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001179 }
1180
1181 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05001182 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07001183 logEntryJson["@odata.id"] =
1184 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" + logEntryID;
1185 logEntryJson["Name"] = "System Event Log Entry";
1186 logEntryJson["Id"] = logEntryID;
1187 logEntryJson["Message"] = std::move(msg);
1188 logEntryJson["MessageId"] = std::move(messageID);
1189 logEntryJson["MessageArgs"] = messageArgs;
1190 logEntryJson["EntryType"] = "Event";
1191 logEntryJson["Severity"] = message->messageSeverity;
1192 logEntryJson["Created"] = std::move(timestamp);
Jason M. Billsac992cd2022-06-24 13:31:46 -07001193 return LogParseError::success;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001194}
1195
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001196inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001197{
Ed Tanous22d268c2022-05-19 09:39:07 -07001198 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001199 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 .methods(boost::beast::http::verb::get)(
1201 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001202 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1203 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001204 query_param::QueryCapabilities capabilities = {
1205 .canDelegateTop = true,
1206 .canDelegateSkip = true,
1207 };
1208 query_param::Query delegatedQuery;
1209 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001210 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001211 {
1212 return;
1213 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001214 if (systemName != "system")
1215 {
1216 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1217 systemName);
1218 return;
1219 }
1220
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001221 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07001222 size_t skip = delegatedQuery.skip.value_or(0);
1223
Ed Tanous002d39b2022-05-31 08:59:27 -07001224 // Collections don't include the static data added by SubRoute
1225 // because it has a duplicate entry for members
1226 asyncResp->res.jsonValue["@odata.type"] =
1227 "#LogEntryCollection.LogEntryCollection";
1228 asyncResp->res.jsonValue["@odata.id"] =
1229 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1230 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1231 asyncResp->res.jsonValue["Description"] =
1232 "Collection of System Event Log Entries";
1233
1234 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1235 logEntryArray = nlohmann::json::array();
1236 // Go through the log files and create a unique ID for each
1237 // entry
1238 std::vector<std::filesystem::path> redfishLogFiles;
1239 getRedfishLogFiles(redfishLogFiles);
1240 uint64_t entryCount = 0;
1241 std::string logEntry;
1242
1243 // Oldest logs are in the last file, so start there and loop
1244 // backwards
1245 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1246 it++)
1247 {
1248 std::ifstream logStream(*it);
1249 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001250 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001251 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001252 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001253
Ed Tanous002d39b2022-05-31 08:59:27 -07001254 // Reset the unique ID on the first entry
1255 bool firstEntry = true;
1256 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001257 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001258 std::string idStr;
1259 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001260 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001261 continue;
1262 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001263 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001264
Jason M. Billsde703c52022-06-23 14:19:04 -07001265 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001266 LogParseError status =
1267 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1268 if (status == LogParseError::messageIdNotInRegistry)
1269 {
1270 continue;
1271 }
1272 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001273 {
1274 messages::internalError(asyncResp->res);
1275 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001276 }
Jason M. Billsde703c52022-06-23 14:19:04 -07001277
Jason M. Billsde703c52022-06-23 14:19:04 -07001278 entryCount++;
1279 // Handle paging using skip (number of entries to skip from the
1280 // start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07001281 if (entryCount <= skip || entryCount > skip + top)
Jason M. Billsde703c52022-06-23 14:19:04 -07001282 {
1283 continue;
1284 }
1285
1286 logEntryArray.push_back(std::move(bmcLogEntry));
Jason M. Bills4978b632022-02-22 14:17:43 -08001287 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001288 }
1289 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001290 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07001291 {
1292 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1293 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07001294 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07001295 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001296 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001297}
Chicago Duan336e96c2019-07-15 14:22:08 +08001298
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001299inline void requestRoutesJournalEventLogEntry(App& app)
1300{
1301 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001302 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001303 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001304 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001305 [&app](const crow::Request& req,
1306 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001307 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001308 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001309 {
1310 return;
1311 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001312
1313 if (systemName != "system")
1314 {
1315 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1316 systemName);
1317 return;
1318 }
1319
Ed Tanous002d39b2022-05-31 08:59:27 -07001320 const std::string& targetID = param;
1321
1322 // Go through the log files and check the unique ID for each
1323 // entry to find the target entry
1324 std::vector<std::filesystem::path> redfishLogFiles;
1325 getRedfishLogFiles(redfishLogFiles);
1326 std::string logEntry;
1327
1328 // Oldest logs are in the last file, so start there and loop
1329 // backwards
1330 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1331 it++)
1332 {
1333 std::ifstream logStream(*it);
1334 if (!logStream.is_open())
1335 {
1336 continue;
1337 }
1338
1339 // Reset the unique ID on the first entry
1340 bool firstEntry = true;
1341 while (std::getline(logStream, logEntry))
1342 {
1343 std::string idStr;
1344 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001345 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001346 continue;
1347 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001348 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001349
1350 if (idStr == targetID)
1351 {
Jason M. Billsde703c52022-06-23 14:19:04 -07001352 nlohmann::json::object_t bmcLogEntry;
Jason M. Billsac992cd2022-06-24 13:31:46 -07001353 LogParseError status =
1354 fillEventLogEntryJson(idStr, logEntry, bmcLogEntry);
1355 if (status != LogParseError::success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001356 {
1357 messages::internalError(asyncResp->res);
1358 return;
1359 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07001360 asyncResp->res.jsonValue.update(bmcLogEntry);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001361 return;
1362 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001363 }
1364 }
1365 // Requested ID was not found
1366 messages::resourceMissingAtURI(asyncResp->res,
1367 crow::utility::urlFromPieces(targetID));
1368 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001369}
1370
1371inline void requestRoutesDBusEventLogEntryCollection(App& app)
1372{
Ed Tanous22d268c2022-05-19 09:39:07 -07001373 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001374 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001375 .methods(boost::beast::http::verb::get)(
1376 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001377 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1378 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001379 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001380 {
1381 return;
1382 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001383 if (systemName != "system")
1384 {
1385 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1386 systemName);
1387 return;
1388 }
1389
Ed Tanous002d39b2022-05-31 08:59:27 -07001390 // Collections don't include the static data added by SubRoute
1391 // because it has a duplicate entry for members
1392 asyncResp->res.jsonValue["@odata.type"] =
1393 "#LogEntryCollection.LogEntryCollection";
1394 asyncResp->res.jsonValue["@odata.id"] =
1395 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1396 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1397 asyncResp->res.jsonValue["Description"] =
1398 "Collection of System Event Log Entries";
1399
1400 // DBus implementation of EventLog/Entries
1401 // Make call to Logging Service to find all log entry objects
1402 crow::connections::systemBus->async_method_call(
1403 [asyncResp](const boost::system::error_code ec,
1404 const dbus::utility::ManagedObjectType& resp) {
1405 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001406 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001407 // TODO Handle for specific error code
1408 BMCWEB_LOG_ERROR
1409 << "getLogEntriesIfaceData resp_handler got error " << ec;
1410 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001411 return;
1412 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001413 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1414 entriesArray = nlohmann::json::array();
1415 for (const auto& objectPath : resp)
1416 {
1417 const uint32_t* id = nullptr;
1418 const uint64_t* timestamp = nullptr;
1419 const uint64_t* updateTimestamp = nullptr;
1420 const std::string* severity = nullptr;
1421 const std::string* message = nullptr;
1422 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001423 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001424 bool resolved = false;
1425 for (const auto& interfaceMap : objectPath.second)
1426 {
1427 if (interfaceMap.first ==
1428 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001429 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001430 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001431 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001432 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001433 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001434 id = std::get_if<uint32_t>(&propertyMap.second);
1435 }
1436 else if (propertyMap.first == "Timestamp")
1437 {
1438 timestamp =
1439 std::get_if<uint64_t>(&propertyMap.second);
1440 }
1441 else if (propertyMap.first == "UpdateTimestamp")
1442 {
1443 updateTimestamp =
1444 std::get_if<uint64_t>(&propertyMap.second);
1445 }
1446 else if (propertyMap.first == "Severity")
1447 {
1448 severity = std::get_if<std::string>(
1449 &propertyMap.second);
1450 }
Vijay Lobo9c11a172021-10-07 16:53:16 -05001451 else if (propertyMap.first == "Resolution")
1452 {
1453 resolution = std::get_if<std::string>(
1454 &propertyMap.second);
1455 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001456 else if (propertyMap.first == "Message")
1457 {
1458 message = std::get_if<std::string>(
1459 &propertyMap.second);
1460 }
1461 else if (propertyMap.first == "Resolved")
1462 {
1463 const bool* resolveptr =
1464 std::get_if<bool>(&propertyMap.second);
1465 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001466 {
1467 messages::internalError(asyncResp->res);
1468 return;
1469 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001470 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001471 }
1472 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001473 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001474 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001475 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001476 messages::internalError(asyncResp->res);
1477 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001478 }
1479 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001480 else if (interfaceMap.first ==
1481 "xyz.openbmc_project.Common.FilePath")
1482 {
1483 for (const auto& propertyMap : interfaceMap.second)
1484 {
1485 if (propertyMap.first == "Path")
1486 {
1487 filePath = std::get_if<std::string>(
1488 &propertyMap.second);
1489 }
1490 }
1491 }
1492 }
1493 // Object path without the
1494 // xyz.openbmc_project.Logging.Entry interface, ignore
1495 // and continue.
1496 if (id == nullptr || message == nullptr ||
1497 severity == nullptr || timestamp == nullptr ||
1498 updateTimestamp == nullptr)
1499 {
1500 continue;
1501 }
1502 entriesArray.push_back({});
1503 nlohmann::json& thisEntry = entriesArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05001504 thisEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001505 thisEntry["@odata.id"] =
1506 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1507 std::to_string(*id);
1508 thisEntry["Name"] = "System Event Log Entry";
1509 thisEntry["Id"] = std::to_string(*id);
1510 thisEntry["Message"] = *message;
1511 thisEntry["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001512 if ((resolution != nullptr) && (!(*resolution).empty()))
1513 {
1514 thisEntry["Resolution"] = *resolution;
1515 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001516 thisEntry["EntryType"] = "Event";
1517 thisEntry["Severity"] =
1518 translateSeverityDbusToRedfish(*severity);
1519 thisEntry["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001520 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001521 thisEntry["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001522 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001523 if (filePath != nullptr)
1524 {
1525 thisEntry["AdditionalDataURI"] =
1526 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1527 std::to_string(*id) + "/attachment";
1528 }
1529 }
1530 std::sort(
1531 entriesArray.begin(), entriesArray.end(),
1532 [](const nlohmann::json& left, const nlohmann::json& right) {
1533 return (left["Id"] <= right["Id"]);
1534 });
1535 asyncResp->res.jsonValue["Members@odata.count"] =
1536 entriesArray.size();
1537 },
1538 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1539 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001540 });
1541}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001542
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001543inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001544{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001545 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001546 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001547 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001548 .methods(boost::beast::http::verb::get)(
1549 [&app](const crow::Request& req,
1550 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001551 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001552 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001553 {
1554 return;
1555 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001556 if (systemName != "system")
1557 {
1558 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1559 systemName);
1560 return;
1561 }
1562
Ed Tanous002d39b2022-05-31 08:59:27 -07001563 std::string entryID = param;
1564 dbus::utility::escapePathForDbus(entryID);
1565
1566 // DBus implementation of EventLog/Entries
1567 // Make call to Logging Service to find all log entry objects
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001568 sdbusplus::asio::getAllProperties(
1569 *crow::connections::systemBus, "xyz.openbmc_project.Logging",
1570 "/xyz/openbmc_project/logging/entry/" + entryID, "",
Ed Tanous002d39b2022-05-31 08:59:27 -07001571 [asyncResp, entryID](const boost::system::error_code ec,
1572 const dbus::utility::DBusPropertiesMap& resp) {
1573 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001574 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001575 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1576 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001577 return;
1578 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001579 if (ec)
1580 {
1581 BMCWEB_LOG_ERROR
1582 << "EventLogEntry (DBus) resp_handler got error " << ec;
1583 messages::internalError(asyncResp->res);
1584 return;
1585 }
1586 const uint32_t* id = nullptr;
1587 const uint64_t* timestamp = nullptr;
1588 const uint64_t* updateTimestamp = nullptr;
1589 const std::string* severity = nullptr;
1590 const std::string* message = nullptr;
1591 const std::string* filePath = nullptr;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001592 const std::string* resolution = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -07001593 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001594
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001595 const bool success = sdbusplus::unpackPropertiesNoThrow(
1596 dbus_utils::UnpackErrorPrinter(), resp, "Id", id, "Timestamp",
1597 timestamp, "UpdateTimestamp", updateTimestamp, "Severity",
Vijay Lobo9c11a172021-10-07 16:53:16 -05001598 severity, "Message", message, "Resolved", resolved,
1599 "Resolution", resolution, "Path", filePath);
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001600
1601 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -07001602 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001603 messages::internalError(asyncResp->res);
1604 return;
Ed Tanous002d39b2022-05-31 08:59:27 -07001605 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001606
Ed Tanous002d39b2022-05-31 08:59:27 -07001607 if (id == nullptr || message == nullptr || severity == nullptr ||
1608 timestamp == nullptr || updateTimestamp == nullptr)
1609 {
1610 messages::internalError(asyncResp->res);
1611 return;
1612 }
1613 asyncResp->res.jsonValue["@odata.type"] =
Vijay Lobo9c11a172021-10-07 16:53:16 -05001614 "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07001615 asyncResp->res.jsonValue["@odata.id"] =
1616 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1617 std::to_string(*id);
1618 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1619 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1620 asyncResp->res.jsonValue["Message"] = *message;
1621 asyncResp->res.jsonValue["Resolved"] = resolved;
Vijay Lobo9c11a172021-10-07 16:53:16 -05001622 if ((resolution != nullptr) && (!(*resolution).empty()))
1623 {
1624 asyncResp->res.jsonValue["Resolution"] = *resolution;
1625 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001626 asyncResp->res.jsonValue["EntryType"] = "Event";
1627 asyncResp->res.jsonValue["Severity"] =
1628 translateSeverityDbusToRedfish(*severity);
1629 asyncResp->res.jsonValue["Created"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001630 redfish::time_utils::getDateTimeUintMs(*timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001631 asyncResp->res.jsonValue["Modified"] =
Ed Tanous2b829372022-08-03 14:22:34 -07001632 redfish::time_utils::getDateTimeUintMs(*updateTimestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07001633 if (filePath != nullptr)
1634 {
1635 asyncResp->res.jsonValue["AdditionalDataURI"] =
1636 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1637 std::to_string(*id) + "/attachment";
1638 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02001639 });
Ed Tanous45ca1b82022-03-25 13:07:27 -07001640 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001641
1642 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001643 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001644 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001645 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001646 [&app](const crow::Request& req,
1647 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001648 const std::string& systemName, const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001649 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001650 {
1651 return;
1652 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001653 if (systemName != "system")
1654 {
1655 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1656 systemName);
1657 return;
1658 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001659 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001660
Ed Tanous002d39b2022-05-31 08:59:27 -07001661 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1662 resolved))
1663 {
1664 return;
1665 }
1666 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001667
Ed Tanous002d39b2022-05-31 08:59:27 -07001668 crow::connections::systemBus->async_method_call(
1669 [asyncResp, entryId](const boost::system::error_code ec) {
1670 if (ec)
1671 {
1672 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1673 messages::internalError(asyncResp->res);
1674 return;
1675 }
1676 },
1677 "xyz.openbmc_project.Logging",
1678 "/xyz/openbmc_project/logging/entry/" + entryId,
1679 "org.freedesktop.DBus.Properties", "Set",
1680 "xyz.openbmc_project.Logging.Entry", "Resolved",
1681 dbus::utility::DbusVariantType(*resolved));
1682 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001683
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001684 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07001685 app, "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001686 .privileges(redfish::privileges::deleteLogEntry)
1687
Ed Tanous002d39b2022-05-31 08:59:27 -07001688 .methods(boost::beast::http::verb::delete_)(
1689 [&app](const crow::Request& req,
1690 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001691 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001692 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001693 {
1694 return;
1695 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001696 if (systemName != "system")
1697 {
1698 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1699 systemName);
1700 return;
1701 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001702 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1703
1704 std::string entryID = param;
1705
1706 dbus::utility::escapePathForDbus(entryID);
1707
1708 // Process response from Logging service.
1709 auto respHandler =
1710 [asyncResp, entryID](const boost::system::error_code ec) {
1711 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1712 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001713 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001714 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001715 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001716 messages::resourceNotFound(asyncResp->res, "LogEntry",
1717 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001718 return;
1719 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001720 // TODO Handle for specific error code
1721 BMCWEB_LOG_ERROR
1722 << "EventLogEntry (DBus) doDelete respHandler got error "
1723 << ec;
1724 asyncResp->res.result(
1725 boost::beast::http::status::internal_server_error);
1726 return;
1727 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001728
Ed Tanous002d39b2022-05-31 08:59:27 -07001729 asyncResp->res.result(boost::beast::http::status::ok);
1730 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001731
Ed Tanous002d39b2022-05-31 08:59:27 -07001732 // Make call to Logging service to request Delete Log
1733 crow::connections::systemBus->async_method_call(
1734 respHandler, "xyz.openbmc_project.Logging",
1735 "/xyz/openbmc_project/logging/entry/" + entryID,
1736 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001737 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001738}
1739
1740inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001741{
George Liu0fda0f12021-11-16 10:06:17 +08001742 BMCWEB_ROUTE(
1743 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001744 "/redfish/v1/Systems/<str>/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001745 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001746 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001747 [&app](const crow::Request& req,
1748 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07001749 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001750 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001751 {
1752 return;
1753 }
Ed Tanous99351cd2022-08-07 16:42:51 -07001754 if (http_helpers::isContentTypeAllowed(
1755 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07001756 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07001757 {
1758 asyncResp->res.result(boost::beast::http::status::bad_request);
1759 return;
1760 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001761 if (systemName != "system")
1762 {
1763 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1764 systemName);
1765 return;
1766 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001767
Ed Tanous002d39b2022-05-31 08:59:27 -07001768 std::string entryID = param;
1769 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001770
Ed Tanous002d39b2022-05-31 08:59:27 -07001771 crow::connections::systemBus->async_method_call(
1772 [asyncResp, entryID](const boost::system::error_code ec,
1773 const sdbusplus::message::unix_fd& unixfd) {
1774 if (ec.value() == EBADR)
1775 {
1776 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1777 entryID);
1778 return;
1779 }
1780 if (ec)
1781 {
1782 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1783 messages::internalError(asyncResp->res);
1784 return;
1785 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001786
Ed Tanous002d39b2022-05-31 08:59:27 -07001787 int fd = -1;
1788 fd = dup(unixfd);
1789 if (fd == -1)
1790 {
1791 messages::internalError(asyncResp->res);
1792 return;
1793 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001794
Ed Tanous002d39b2022-05-31 08:59:27 -07001795 long long int size = lseek(fd, 0, SEEK_END);
1796 if (size == -1)
1797 {
1798 messages::internalError(asyncResp->res);
1799 return;
1800 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001801
Ed Tanous002d39b2022-05-31 08:59:27 -07001802 // Arbitrary max size of 64kb
1803 constexpr int maxFileSize = 65536;
1804 if (size > maxFileSize)
1805 {
1806 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1807 << maxFileSize;
1808 messages::internalError(asyncResp->res);
1809 return;
1810 }
1811 std::vector<char> data(static_cast<size_t>(size));
1812 long long int rc = lseek(fd, 0, SEEK_SET);
1813 if (rc == -1)
1814 {
1815 messages::internalError(asyncResp->res);
1816 return;
1817 }
1818 rc = read(fd, data.data(), data.size());
1819 if ((rc == -1) || (rc != size))
1820 {
1821 messages::internalError(asyncResp->res);
1822 return;
1823 }
1824 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001825
Ed Tanous002d39b2022-05-31 08:59:27 -07001826 std::string_view strData(data.data(), data.size());
1827 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001828
Ed Tanousd9f6c622022-03-17 09:12:17 -07001829 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07001831 asyncResp->res.addHeader(
1832 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07001833 asyncResp->res.body() = std::move(output);
1834 },
1835 "xyz.openbmc_project.Logging",
1836 "/xyz/openbmc_project/logging/entry/" + entryID,
1837 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1838 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001839}
1840
Spencer Kub7028eb2021-10-26 15:27:35 +08001841constexpr const char* hostLoggerFolderPath = "/var/log/console";
1842
1843inline bool
1844 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1845 std::vector<std::filesystem::path>& hostLoggerFiles)
1846{
1847 std::error_code ec;
1848 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1849 if (ec)
1850 {
1851 BMCWEB_LOG_ERROR << ec.message();
1852 return false;
1853 }
1854 for (const std::filesystem::directory_entry& it : logPath)
1855 {
1856 std::string filename = it.path().filename();
1857 // Prefix of each log files is "log". Find the file and save the
1858 // path
Ed Tanous11ba3972022-07-11 09:50:41 -07001859 if (filename.starts_with("log"))
Spencer Kub7028eb2021-10-26 15:27:35 +08001860 {
1861 hostLoggerFiles.emplace_back(it.path());
1862 }
1863 }
1864 // As the log files rotate, they are appended with a ".#" that is higher for
1865 // the older logs. Since we start from oldest logs, sort the name in
1866 // descending order.
1867 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1868 AlphanumLess<std::string>());
1869
1870 return true;
1871}
1872
Ed Tanous02cad962022-06-30 16:50:15 -07001873inline bool getHostLoggerEntries(
1874 const std::vector<std::filesystem::path>& hostLoggerFiles, uint64_t skip,
1875 uint64_t top, std::vector<std::string>& logEntries, size_t& logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001876{
1877 GzFileReader logFile;
1878
1879 // Go though all log files and expose host logs.
1880 for (const std::filesystem::path& it : hostLoggerFiles)
1881 {
1882 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1883 {
1884 BMCWEB_LOG_ERROR << "fail to expose host logs";
1885 return false;
1886 }
1887 }
1888 // Get lastMessage from constructor by getter
1889 std::string lastMessage = logFile.getLastMessage();
1890 if (!lastMessage.empty())
1891 {
1892 logCount++;
1893 if (logCount > skip && logCount <= (skip + top))
1894 {
1895 logEntries.push_back(lastMessage);
1896 }
1897 }
1898 return true;
1899}
1900
1901inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1902 const std::string& msg,
Jason M. Bills6d6574c2022-06-28 12:30:16 -07001903 nlohmann::json::object_t& logEntryJson)
Spencer Kub7028eb2021-10-26 15:27:35 +08001904{
1905 // Fill in the log entry with the gathered data.
Vijay Lobo9c11a172021-10-07 16:53:16 -05001906 logEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills6d6574c2022-06-28 12:30:16 -07001907 logEntryJson["@odata.id"] =
1908 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1909 logEntryID;
1910 logEntryJson["Name"] = "Host Logger Entry";
1911 logEntryJson["Id"] = logEntryID;
1912 logEntryJson["Message"] = msg;
1913 logEntryJson["EntryType"] = "Oem";
1914 logEntryJson["Severity"] = "OK";
1915 logEntryJson["OemRecordFormat"] = "Host Logger Entry";
Spencer Kub7028eb2021-10-26 15:27:35 +08001916}
1917
1918inline void requestRoutesSystemHostLogger(App& app)
1919{
Ed Tanous22d268c2022-05-19 09:39:07 -07001920 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/")
Spencer Kub7028eb2021-10-26 15:27:35 +08001921 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07001922 .methods(boost::beast::http::verb::get)(
1923 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001924 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1925 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001926 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001927 {
1928 return;
1929 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001930 if (systemName != "system")
1931 {
1932 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1933 systemName);
1934 return;
1935 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001936 asyncResp->res.jsonValue["@odata.id"] =
1937 "/redfish/v1/Systems/system/LogServices/HostLogger";
1938 asyncResp->res.jsonValue["@odata.type"] =
1939 "#LogService.v1_1_0.LogService";
1940 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1941 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1942 asyncResp->res.jsonValue["Id"] = "HostLogger";
1943 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1944 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1945 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001946}
1947
1948inline void requestRoutesSystemHostLoggerCollection(App& app)
1949{
1950 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07001951 "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/")
Spencer Kub7028eb2021-10-26 15:27:35 +08001952 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001953 .methods(boost::beast::http::verb::get)(
1954 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07001955 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1956 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07001957 query_param::QueryCapabilities capabilities = {
1958 .canDelegateTop = true,
1959 .canDelegateSkip = true,
1960 };
1961 query_param::Query delegatedQuery;
1962 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001963 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001964 {
1965 return;
1966 }
Ed Tanous22d268c2022-05-19 09:39:07 -07001967 if (systemName != "system")
1968 {
1969 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1970 systemName);
1971 return;
1972 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001973 asyncResp->res.jsonValue["@odata.id"] =
1974 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1975 asyncResp->res.jsonValue["@odata.type"] =
1976 "#LogEntryCollection.LogEntryCollection";
1977 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1978 asyncResp->res.jsonValue["Description"] =
1979 "Collection of HostLogger Entries";
1980 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1981 logEntryArray = nlohmann::json::array();
1982 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001983
Ed Tanous002d39b2022-05-31 08:59:27 -07001984 std::vector<std::filesystem::path> hostLoggerFiles;
1985 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1986 {
1987 BMCWEB_LOG_ERROR << "fail to get host log file path";
1988 return;
1989 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07001990 // If we weren't provided top and skip limits, use the defaults.
1991 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08001992 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous002d39b2022-05-31 08:59:27 -07001993 size_t logCount = 0;
1994 // This vector only store the entries we want to expose that
1995 // control by skip and top.
1996 std::vector<std::string> logEntries;
Ed Tanous3648c8b2022-07-25 13:39:59 -07001997 if (!getHostLoggerEntries(hostLoggerFiles, skip, top, logEntries,
1998 logCount))
Ed Tanous002d39b2022-05-31 08:59:27 -07001999 {
2000 messages::internalError(asyncResp->res);
2001 return;
2002 }
2003 // If vector is empty, that means skip value larger than total
2004 // log count
2005 if (logEntries.empty())
2006 {
2007 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
2008 return;
2009 }
2010 if (!logEntries.empty())
2011 {
2012 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08002013 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002014 nlohmann::json::object_t hostLogEntry;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002015 fillHostLoggerEntryJson(std::to_string(skip + i), logEntries[i],
2016 hostLogEntry);
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002017 logEntryArray.push_back(std::move(hostLogEntry));
George Liu0fda0f12021-11-16 10:06:17 +08002018 }
2019
Ed Tanous002d39b2022-05-31 08:59:27 -07002020 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002021 if (skip + top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08002022 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002023 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2024 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002025 std::to_string(skip + top);
George Liu0fda0f12021-11-16 10:06:17 +08002026 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002027 }
George Liu0fda0f12021-11-16 10:06:17 +08002028 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002029}
2030
2031inline void requestRoutesSystemHostLoggerLogEntry(App& app)
2032{
2033 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07002034 app, "/redfish/v1/Systems/<str>/LogServices/HostLogger/Entries/<str>/")
Spencer Kub7028eb2021-10-26 15:27:35 +08002035 .privileges(redfish::privileges::getLogEntry)
2036 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002037 [&app](const crow::Request& req,
2038 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07002039 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002040 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002041 {
2042 return;
2043 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002044 if (systemName != "system")
2045 {
2046 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2047 systemName);
2048 return;
2049 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002050 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08002051
Ed Tanous002d39b2022-05-31 08:59:27 -07002052 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08002053
Ed Tanous002d39b2022-05-31 08:59:27 -07002054 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
2055 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08002056
Ed Tanous002d39b2022-05-31 08:59:27 -07002057 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
2058 if (ec == std::errc::invalid_argument)
2059 {
2060 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2061 return;
2062 }
2063 if (ec == std::errc::result_out_of_range)
2064 {
2065 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2066 return;
2067 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002068
Ed Tanous002d39b2022-05-31 08:59:27 -07002069 std::vector<std::filesystem::path> hostLoggerFiles;
2070 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
2071 {
2072 BMCWEB_LOG_ERROR << "fail to get host log file path";
2073 return;
2074 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002075
Ed Tanous002d39b2022-05-31 08:59:27 -07002076 size_t logCount = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002077 size_t top = 1;
Ed Tanous002d39b2022-05-31 08:59:27 -07002078 std::vector<std::string> logEntries;
2079 // We can get specific entry by skip and top. For example, if we
2080 // want to get nth entry, we can set skip = n-1 and top = 1 to
2081 // get that entry
2082 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
2083 logCount))
2084 {
2085 messages::internalError(asyncResp->res);
2086 return;
2087 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002088
Ed Tanous002d39b2022-05-31 08:59:27 -07002089 if (!logEntries.empty())
2090 {
Jason M. Bills6d6574c2022-06-28 12:30:16 -07002091 nlohmann::json::object_t hostLogEntry;
2092 fillHostLoggerEntryJson(targetID, logEntries[0], hostLogEntry);
2093 asyncResp->res.jsonValue.update(hostLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002094 return;
2095 }
Spencer Kub7028eb2021-10-26 15:27:35 +08002096
Ed Tanous002d39b2022-05-31 08:59:27 -07002097 // Requested ID was not found
2098 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2099 });
Spencer Kub7028eb2021-10-26 15:27:35 +08002100}
2101
Claire Weinanfdd26902022-03-01 14:18:25 -08002102constexpr char const* dumpManagerIface =
2103 "xyz.openbmc_project.Collection.DeleteAll";
Claire Weinandd72e872022-08-15 14:20:06 -07002104inline void handleBMCLogServicesCollectionGet(
Claire Weinanfdd26902022-03-01 14:18:25 -08002105 crow::App& app, const crow::Request& req,
2106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2107{
2108 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2109 {
2110 return;
2111 }
2112 // Collections don't include the static data added by SubRoute
2113 // because it has a duplicate entry for members
2114 asyncResp->res.jsonValue["@odata.type"] =
2115 "#LogServiceCollection.LogServiceCollection";
2116 asyncResp->res.jsonValue["@odata.id"] =
2117 "/redfish/v1/Managers/bmc/LogServices";
2118 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2119 asyncResp->res.jsonValue["Description"] =
2120 "Collection of LogServices for this Manager";
2121 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2122 logServiceArray = nlohmann::json::array();
2123
2124#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous613dabe2022-07-09 11:17:36 -07002125 nlohmann::json::object_t journal;
2126 journal["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/Journal";
2127 logServiceArray.push_back(std::move(journal));
Claire Weinanfdd26902022-03-01 14:18:25 -08002128#endif
2129
2130 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2131
2132#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2133 auto respHandler =
2134 [asyncResp](
2135 const boost::system::error_code ec,
2136 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2137 if (ec)
2138 {
2139 BMCWEB_LOG_ERROR
Claire Weinandd72e872022-08-15 14:20:06 -07002140 << "handleBMCLogServicesCollectionGet respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -08002141 << ec;
2142 // Assume that getting an error simply means there are no dump
2143 // LogServices. Return without adding any error response.
2144 return;
2145 }
2146
2147 nlohmann::json& logServiceArrayLocal =
2148 asyncResp->res.jsonValue["Members"];
2149
2150 for (const std::string& path : subTreePaths)
2151 {
2152 if (path == "/xyz/openbmc_project/dump/bmc")
2153 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002154 nlohmann::json::object_t member;
2155 member["@odata.id"] =
2156 "/redfish/v1/Managers/bmc/LogServices/Dump";
2157 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002158 }
2159 else if (path == "/xyz/openbmc_project/dump/faultlog")
2160 {
Ed Tanous613dabe2022-07-09 11:17:36 -07002161 nlohmann::json::object_t member;
2162 member["@odata.id"] =
2163 "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2164 logServiceArrayLocal.push_back(std::move(member));
Claire Weinanfdd26902022-03-01 14:18:25 -08002165 }
2166 }
2167
2168 asyncResp->res.jsonValue["Members@odata.count"] =
2169 logServiceArrayLocal.size();
2170 };
2171
2172 crow::connections::systemBus->async_method_call(
2173 respHandler, "xyz.openbmc_project.ObjectMapper",
2174 "/xyz/openbmc_project/object_mapper",
2175 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2176 "/xyz/openbmc_project/dump", 0,
2177 std::array<const char*, 1>{dumpManagerIface});
2178#endif
2179}
2180
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002181inline void requestRoutesBMCLogServiceCollection(App& app)
2182{
2183 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002184 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002185 .methods(boost::beast::http::verb::get)(
Claire Weinandd72e872022-08-15 14:20:06 -07002186 std::bind_front(handleBMCLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002187}
Ed Tanous1da66f72018-07-27 16:13:37 -07002188
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002189inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002190{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002191 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002192 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002193 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002194 [&app](const crow::Request& req,
2195 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002196 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002197 {
2198 return;
2199 }
2200 asyncResp->res.jsonValue["@odata.type"] =
2201 "#LogService.v1_1_0.LogService";
2202 asyncResp->res.jsonValue["@odata.id"] =
2203 "/redfish/v1/Managers/bmc/LogServices/Journal";
2204 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2205 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2206 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2207 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302208
Ed Tanous002d39b2022-05-31 08:59:27 -07002209 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002210 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002211 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2212 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2213 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302214
Ed Tanous002d39b2022-05-31 08:59:27 -07002215 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2216 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2217 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002218}
Jason M. Billse1f26342018-07-18 12:12:00 -07002219
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002220static int
2221 fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2222 sd_journal* journal,
2223 nlohmann::json::object_t& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002224{
2225 // Get the Log Entry contents
2226 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002227
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002228 std::string message;
2229 std::string_view syslogID;
2230 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2231 if (ret < 0)
2232 {
2233 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2234 << strerror(-ret);
2235 }
2236 if (!syslogID.empty())
2237 {
2238 message += std::string(syslogID) + ": ";
2239 }
2240
Ed Tanous39e77502019-03-04 17:35:53 -08002241 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002242 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002243 if (ret < 0)
2244 {
2245 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2246 return 1;
2247 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002248 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002249
2250 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002251 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002252 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002253 if (ret < 0)
2254 {
2255 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002256 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002257
2258 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002259 std::string entryTimeStr;
2260 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002261 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002262 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002263 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002264
2265 // Fill in the log entry with the gathered data
Vijay Lobo9c11a172021-10-07 16:53:16 -05002266 bmcJournalLogEntryJson["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002267 bmcJournalLogEntryJson["@odata.id"] =
2268 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2269 bmcJournalLogEntryID;
2270 bmcJournalLogEntryJson["Name"] = "BMC Journal Entry";
2271 bmcJournalLogEntryJson["Id"] = bmcJournalLogEntryID;
2272 bmcJournalLogEntryJson["Message"] = std::move(message);
2273 bmcJournalLogEntryJson["EntryType"] = "Oem";
2274 bmcJournalLogEntryJson["Severity"] = severity <= 2 ? "Critical"
2275 : severity <= 4 ? "Warning"
2276 : "OK";
2277 bmcJournalLogEntryJson["OemRecordFormat"] = "BMC Journal Entry";
2278 bmcJournalLogEntryJson["Created"] = std::move(entryTimeStr);
Jason M. Billse1f26342018-07-18 12:12:00 -07002279 return 0;
2280}
2281
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002282inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002283{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002284 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002285 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002286 .methods(boost::beast::http::verb::get)(
2287 [&app](const crow::Request& req,
2288 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2289 query_param::QueryCapabilities capabilities = {
2290 .canDelegateTop = true,
2291 .canDelegateSkip = true,
2292 };
2293 query_param::Query delegatedQuery;
2294 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002295 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002296 {
2297 return;
2298 }
Ed Tanous3648c8b2022-07-25 13:39:59 -07002299
2300 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08002301 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07002302
Ed Tanous002d39b2022-05-31 08:59:27 -07002303 // Collections don't include the static data added by SubRoute
2304 // because it has a duplicate entry for members
2305 asyncResp->res.jsonValue["@odata.type"] =
2306 "#LogEntryCollection.LogEntryCollection";
2307 asyncResp->res.jsonValue["@odata.id"] =
2308 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2309 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2310 asyncResp->res.jsonValue["Description"] =
2311 "Collection of BMC Journal Entries";
2312 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2313 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002314
Ed Tanous002d39b2022-05-31 08:59:27 -07002315 // Go through the journal and use the timestamp to create a
2316 // unique ID for each entry
2317 sd_journal* journalTmp = nullptr;
2318 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2319 if (ret < 0)
2320 {
2321 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2322 messages::internalError(asyncResp->res);
2323 return;
2324 }
2325 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2326 journalTmp, sd_journal_close);
2327 journalTmp = nullptr;
2328 uint64_t entryCount = 0;
2329 // Reset the unique ID on the first entry
2330 bool firstEntry = true;
2331 SD_JOURNAL_FOREACH(journal.get())
2332 {
2333 entryCount++;
2334 // Handle paging using skip (number of entries to skip from
2335 // the start) and top (number of entries to display)
Ed Tanous3648c8b2022-07-25 13:39:59 -07002336 if (entryCount <= skip || entryCount > skip + top)
George Liu0fda0f12021-11-16 10:06:17 +08002337 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002338 continue;
2339 }
2340
2341 std::string idStr;
2342 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2343 {
2344 continue;
2345 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002346 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002347
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002348 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002349 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2350 bmcJournalLogEntry) != 0)
2351 {
George Liu0fda0f12021-11-16 10:06:17 +08002352 messages::internalError(asyncResp->res);
2353 return;
2354 }
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002355 logEntryArray.push_back(std::move(bmcJournalLogEntry));
Ed Tanous002d39b2022-05-31 08:59:27 -07002356 }
2357 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanous3648c8b2022-07-25 13:39:59 -07002358 if (skip + top < entryCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07002359 {
2360 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2361 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanous3648c8b2022-07-25 13:39:59 -07002362 std::to_string(skip + top);
Ed Tanous002d39b2022-05-31 08:59:27 -07002363 }
George Liu0fda0f12021-11-16 10:06:17 +08002364 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002365}
Jason M. Billse1f26342018-07-18 12:12:00 -07002366
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002367inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002368{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002369 BMCWEB_ROUTE(app,
2370 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002371 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002372 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002373 [&app](const crow::Request& req,
2374 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2375 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002376 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002377 {
2378 return;
2379 }
2380 // Convert the unique ID back to a timestamp to find the entry
2381 uint64_t ts = 0;
2382 uint64_t index = 0;
2383 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2384 {
2385 return;
2386 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002387
Ed Tanous002d39b2022-05-31 08:59:27 -07002388 sd_journal* journalTmp = nullptr;
2389 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2390 if (ret < 0)
2391 {
2392 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2393 messages::internalError(asyncResp->res);
2394 return;
2395 }
2396 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2397 journalTmp, sd_journal_close);
2398 journalTmp = nullptr;
2399 // Go to the timestamp in the log and move to the entry at the
2400 // index tracking the unique ID
2401 std::string idStr;
2402 bool firstEntry = true;
2403 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2404 if (ret < 0)
2405 {
2406 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2407 << strerror(-ret);
2408 messages::internalError(asyncResp->res);
2409 return;
2410 }
2411 for (uint64_t i = 0; i <= index; i++)
2412 {
2413 sd_journal_next(journal.get());
2414 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2415 {
2416 messages::internalError(asyncResp->res);
2417 return;
2418 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002419 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002420 }
2421 // Confirm that the entry ID matches what was requested
2422 if (idStr != entryID)
2423 {
2424 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2425 return;
2426 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002427
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002428 nlohmann::json::object_t bmcJournalLogEntry;
Ed Tanous002d39b2022-05-31 08:59:27 -07002429 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
Jason M. Bills3a48b3a2022-06-24 10:10:15 -07002430 bmcJournalLogEntry) != 0)
Ed Tanous002d39b2022-05-31 08:59:27 -07002431 {
2432 messages::internalError(asyncResp->res);
2433 return;
2434 }
Jason M. Billsd405bb52022-06-24 10:52:05 -07002435 asyncResp->res.jsonValue.update(bmcJournalLogEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002436 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002437}
2438
Claire Weinanfdd26902022-03-01 14:18:25 -08002439inline void
2440 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2441 const std::string& dumpType)
2442{
2443 std::string dumpPath;
2444 std::string overWritePolicy;
2445 bool collectDiagnosticDataSupported = false;
2446
2447 if (dumpType == "BMC")
2448 {
2449 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2450 overWritePolicy = "WrapsWhenFull";
2451 collectDiagnosticDataSupported = true;
2452 }
2453 else if (dumpType == "FaultLog")
2454 {
2455 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2456 overWritePolicy = "Unknown";
2457 collectDiagnosticDataSupported = false;
2458 }
2459 else if (dumpType == "System")
2460 {
2461 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2462 overWritePolicy = "WrapsWhenFull";
2463 collectDiagnosticDataSupported = true;
2464 }
2465 else
2466 {
2467 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2468 << dumpType;
2469 messages::internalError(asyncResp->res);
2470 return;
2471 }
2472
2473 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2474 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2475 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2476 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2477 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2478 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2479
2480 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002481 redfish::time_utils::getDateTimeOffsetNow();
Claire Weinanfdd26902022-03-01 14:18:25 -08002482 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2483 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2484 redfishDateTimeOffset.second;
2485
2486 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2487 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2488 dumpPath + "/Actions/LogService.ClearLog";
2489
2490 if (collectDiagnosticDataSupported)
2491 {
2492 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2493 ["target"] =
2494 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2495 }
2496}
2497
2498inline void handleLogServicesDumpServiceGet(
2499 crow::App& app, const std::string& dumpType, const crow::Request& req,
2500 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2501{
2502 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2503 {
2504 return;
2505 }
2506 getDumpServiceInfo(asyncResp, dumpType);
2507}
2508
Ed Tanous22d268c2022-05-19 09:39:07 -07002509inline void handleLogServicesDumpServiceComputerSystemGet(
2510 crow::App& app, const crow::Request& req,
2511 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2512 const std::string& chassisId)
2513{
2514 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2515 {
2516 return;
2517 }
2518 if (chassisId != "system")
2519 {
2520 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2521 return;
2522 }
2523 getDumpServiceInfo(asyncResp, "System");
2524}
2525
Claire Weinanfdd26902022-03-01 14:18:25 -08002526inline void handleLogServicesDumpEntriesCollectionGet(
2527 crow::App& app, const std::string& dumpType, const crow::Request& req,
2528 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2529{
2530 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2531 {
2532 return;
2533 }
2534 getDumpEntryCollection(asyncResp, dumpType);
2535}
2536
Ed Tanous22d268c2022-05-19 09:39:07 -07002537inline void handleLogServicesDumpEntriesCollectionComputerSystemGet(
2538 crow::App& app, const crow::Request& req,
2539 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2540 const std::string& chassisId)
2541{
2542 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2543 {
2544 return;
2545 }
2546 if (chassisId != "system")
2547 {
2548 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2549 return;
2550 }
2551 getDumpEntryCollection(asyncResp, "System");
2552}
2553
Claire Weinanfdd26902022-03-01 14:18:25 -08002554inline void handleLogServicesDumpEntryGet(
2555 crow::App& app, const std::string& dumpType, const crow::Request& req,
2556 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2557 const std::string& dumpId)
2558{
2559 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2560 {
2561 return;
2562 }
2563 getDumpEntryById(asyncResp, dumpId, dumpType);
2564}
Ed Tanous22d268c2022-05-19 09:39:07 -07002565inline void handleLogServicesDumpEntryComputerSystemGet(
2566 crow::App& app, const crow::Request& req,
2567 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2568 const std::string& chassisId, const std::string& dumpId)
2569{
2570 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2571 {
2572 return;
2573 }
2574 if (chassisId != "system")
2575 {
2576 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2577 return;
2578 }
2579 getDumpEntryById(asyncResp, dumpId, "System");
2580}
Claire Weinanfdd26902022-03-01 14:18:25 -08002581
2582inline void handleLogServicesDumpEntryDelete(
2583 crow::App& app, const std::string& dumpType, const crow::Request& req,
2584 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2585 const std::string& dumpId)
2586{
2587 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2588 {
2589 return;
2590 }
2591 deleteDumpEntry(asyncResp, dumpId, dumpType);
2592}
2593
Ed Tanous22d268c2022-05-19 09:39:07 -07002594inline void handleLogServicesDumpEntryComputerSystemDelete(
2595 crow::App& app, const crow::Request& req,
2596 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2597 const std::string& chassisId, const std::string& dumpId)
2598{
2599 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2600 {
2601 return;
2602 }
2603 if (chassisId != "system")
2604 {
2605 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2606 return;
2607 }
2608 deleteDumpEntry(asyncResp, dumpId, "System");
2609}
2610
Claire Weinanfdd26902022-03-01 14:18:25 -08002611inline void handleLogServicesDumpCollectDiagnosticDataPost(
2612 crow::App& app, const std::string& dumpType, const crow::Request& req,
2613 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2614{
2615 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2616 {
2617 return;
2618 }
2619 createDump(asyncResp, req, dumpType);
2620}
2621
Ed Tanous22d268c2022-05-19 09:39:07 -07002622inline void handleLogServicesDumpCollectDiagnosticDataComputerSystemPost(
2623 crow::App& app, const crow::Request& req,
2624 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2625 const std::string& chassisId)
2626{
2627 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2628 {
2629 return;
2630 }
2631 if (chassisId != "system")
2632 {
2633 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2634 return;
2635 }
2636 createDump(asyncResp, req, "System");
2637}
2638
Claire Weinanfdd26902022-03-01 14:18:25 -08002639inline void handleLogServicesDumpClearLogPost(
2640 crow::App& app, const std::string& dumpType, const crow::Request& req,
2641 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2642{
2643 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2644 {
2645 return;
2646 }
2647 clearDump(asyncResp, dumpType);
2648}
2649
Ed Tanous22d268c2022-05-19 09:39:07 -07002650inline void handleLogServicesDumpClearLogComputerSystemPost(
2651 crow::App& app, const crow::Request& req,
2652 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2653 const std::string& chassisId)
2654{
2655 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2656 {
2657 return;
2658 }
2659 if (chassisId != "system")
2660 {
2661 messages::resourceNotFound(asyncResp->res, "ComputerSystem", chassisId);
2662 return;
2663 }
2664 clearDump(asyncResp, "System");
2665}
2666
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002667inline void requestRoutesBMCDumpService(App& app)
2668{
2669 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002670 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002671 .methods(boost::beast::http::verb::get)(std::bind_front(
2672 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002673}
2674
2675inline void requestRoutesBMCDumpEntryCollection(App& app)
2676{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002677 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002678 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002679 .methods(boost::beast::http::verb::get)(std::bind_front(
2680 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002681}
2682
2683inline void requestRoutesBMCDumpEntry(App& app)
2684{
2685 BMCWEB_ROUTE(app,
2686 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002687 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002688 .methods(boost::beast::http::verb::get)(std::bind_front(
2689 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2690
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002691 BMCWEB_ROUTE(app,
2692 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002693 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002694 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2695 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002696}
2697
2698inline void requestRoutesBMCDumpCreate(App& app)
2699{
George Liu0fda0f12021-11-16 10:06:17 +08002700 BMCWEB_ROUTE(
2701 app,
2702 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002703 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002704 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002705 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2706 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002707}
2708
2709inline void requestRoutesBMCDumpClear(App& app)
2710{
George Liu0fda0f12021-11-16 10:06:17 +08002711 BMCWEB_ROUTE(
2712 app,
2713 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002714 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002715 .methods(boost::beast::http::verb::post)(std::bind_front(
2716 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2717}
2718
2719inline void requestRoutesFaultLogDumpService(App& app)
2720{
2721 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2722 .privileges(redfish::privileges::getLogService)
2723 .methods(boost::beast::http::verb::get)(std::bind_front(
2724 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2725}
2726
2727inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2728{
2729 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2730 .privileges(redfish::privileges::getLogEntryCollection)
2731 .methods(boost::beast::http::verb::get)(
2732 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2733 std::ref(app), "FaultLog"));
2734}
2735
2736inline void requestRoutesFaultLogDumpEntry(App& app)
2737{
2738 BMCWEB_ROUTE(app,
2739 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2740 .privileges(redfish::privileges::getLogEntry)
2741 .methods(boost::beast::http::verb::get)(std::bind_front(
2742 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2743
2744 BMCWEB_ROUTE(app,
2745 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2746 .privileges(redfish::privileges::deleteLogEntry)
2747 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2748 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2749}
2750
2751inline void requestRoutesFaultLogDumpClear(App& app)
2752{
2753 BMCWEB_ROUTE(
2754 app,
2755 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2756 .privileges(redfish::privileges::postLogService)
2757 .methods(boost::beast::http::verb::post)(std::bind_front(
2758 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002759}
2760
2761inline void requestRoutesSystemDumpService(App& app)
2762{
Ed Tanous22d268c2022-05-19 09:39:07 -07002763 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002764 .privileges(redfish::privileges::getLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002765 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002766 handleLogServicesDumpServiceComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002767}
2768
2769inline void requestRoutesSystemDumpEntryCollection(App& app)
2770{
Ed Tanous22d268c2022-05-19 09:39:07 -07002771 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002772 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous22d268c2022-05-19 09:39:07 -07002773 .methods(boost::beast::http::verb::get)(std::bind_front(
2774 handleLogServicesDumpEntriesCollectionComputerSystemGet,
2775 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002776}
2777
2778inline void requestRoutesSystemDumpEntry(App& app)
2779{
2780 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002781 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002782 .privileges(redfish::privileges::getLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002783 .methods(boost::beast::http::verb::get)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002784 handleLogServicesDumpEntryComputerSystemGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002785
2786 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002787 "/redfish/v1/Systems/<str>/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002788 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002789 .methods(boost::beast::http::verb::delete_)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002790 handleLogServicesDumpEntryComputerSystemDelete, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002791}
2792
2793inline void requestRoutesSystemDumpCreate(App& app)
2794{
George Liu0fda0f12021-11-16 10:06:17 +08002795 BMCWEB_ROUTE(
2796 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002797 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002798 .privileges(redfish::privileges::postLogService)
Ed Tanous22d268c2022-05-19 09:39:07 -07002799 .methods(boost::beast::http::verb::post)(std::bind_front(
2800 handleLogServicesDumpCollectDiagnosticDataComputerSystemPost,
2801 std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002802}
2803
2804inline void requestRoutesSystemDumpClear(App& app)
2805{
George Liu0fda0f12021-11-16 10:06:17 +08002806 BMCWEB_ROUTE(
2807 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002808 "/redfish/v1/Systems/<str>/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002809 .privileges(redfish::privileges::postLogService)
Claire Weinan6ab9ad52022-08-12 18:20:17 -07002810 .methods(boost::beast::http::verb::post)(std::bind_front(
Ed Tanous22d268c2022-05-19 09:39:07 -07002811 handleLogServicesDumpClearLogComputerSystemPost, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002812}
2813
2814inline void requestRoutesCrashdumpService(App& app)
2815{
2816 // Note: Deviated from redfish privilege registry for GET & HEAD
2817 // method for security reasons.
2818 /**
2819 * Functions triggers appropriate requests on DBus
2820 */
Ed Tanous22d268c2022-05-19 09:39:07 -07002821 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002822 // This is incorrect, should be:
2823 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002824 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002825 .methods(boost::beast::http::verb::get)(
2826 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002827 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2828 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002829 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002830 {
2831 return;
2832 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002833 if (systemName != "system")
2834 {
2835 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2836 systemName);
2837 return;
2838 }
2839
Ed Tanous002d39b2022-05-31 08:59:27 -07002840 // Copy over the static data to include the entries added by
2841 // SubRoute
2842 asyncResp->res.jsonValue["@odata.id"] =
2843 "/redfish/v1/Systems/system/LogServices/Crashdump";
2844 asyncResp->res.jsonValue["@odata.type"] =
2845 "#LogService.v1_2_0.LogService";
2846 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2847 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2848 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2849 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2850 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302851
Ed Tanous002d39b2022-05-31 08:59:27 -07002852 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07002853 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07002854 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2855 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2856 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302857
Ed Tanous002d39b2022-05-31 08:59:27 -07002858 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2859 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2860 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2861 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2862 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2863 ["target"] =
2864 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002865 });
2866}
2867
2868void inline requestRoutesCrashdumpClear(App& app)
2869{
George Liu0fda0f12021-11-16 10:06:17 +08002870 BMCWEB_ROUTE(
2871 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002872 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002873 // This is incorrect, should be:
2874 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002875 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002876 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002877 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2879 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002880 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002881 {
2882 return;
2883 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002884 if (systemName != "system")
2885 {
2886 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2887 systemName);
2888 return;
2889 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002890 crow::connections::systemBus->async_method_call(
2891 [asyncResp](const boost::system::error_code ec,
2892 const std::string&) {
2893 if (ec)
2894 {
2895 messages::internalError(asyncResp->res);
2896 return;
2897 }
2898 messages::success(asyncResp->res);
2899 },
2900 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2901 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002902}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002903
zhanghch058d1b46d2021-04-01 11:18:24 +08002904static void
2905 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2906 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002907{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002908 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002909 [asyncResp, logID,
2910 &logEntryJson](const boost::system::error_code ec,
2911 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002912 if (ec)
2913 {
2914 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2915 if (ec.value() ==
2916 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002917 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002918 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002919 }
2920 else
2921 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002922 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002923 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002924 return;
2925 }
2926
2927 std::string timestamp{};
2928 std::string filename{};
2929 std::string logfile{};
2930 parseCrashdumpParameters(params, filename, timestamp, logfile);
2931
2932 if (filename.empty() || timestamp.empty())
2933 {
2934 messages::resourceMissingAtURI(asyncResp->res,
2935 crow::utility::urlFromPieces(logID));
2936 return;
2937 }
2938
2939 std::string crashdumpURI =
2940 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2941 logID + "/" + filename;
Jason M. Bills84afc482022-06-24 12:38:23 -07002942 nlohmann::json::object_t logEntry;
Vijay Lobo9c11a172021-10-07 16:53:16 -05002943 logEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07002944 logEntry["@odata.id"] =
2945 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" + logID;
2946 logEntry["Name"] = "CPU Crashdump";
2947 logEntry["Id"] = logID;
2948 logEntry["EntryType"] = "Oem";
2949 logEntry["AdditionalDataURI"] = std::move(crashdumpURI);
2950 logEntry["DiagnosticDataType"] = "OEM";
2951 logEntry["OEMDiagnosticDataType"] = "PECICrashdump";
2952 logEntry["Created"] = std::move(timestamp);
Ed Tanous002d39b2022-05-31 08:59:27 -07002953
2954 // If logEntryJson references an array of LogEntry resources
2955 // ('Members' list), then push this as a new entry, otherwise set it
2956 // directly
2957 if (logEntryJson.is_array())
2958 {
2959 logEntryJson.push_back(logEntry);
2960 asyncResp->res.jsonValue["Members@odata.count"] =
2961 logEntryJson.size();
2962 }
2963 else
2964 {
Jason M. Billsd405bb52022-06-24 10:52:05 -07002965 logEntryJson.update(logEntry);
Ed Tanous002d39b2022-05-31 08:59:27 -07002966 }
2967 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02002968 sdbusplus::asio::getAllProperties(
2969 *crow::connections::systemBus, crashdumpObject,
2970 crashdumpPath + std::string("/") + logID, crashdumpInterface,
2971 std::move(getStoredLogCallback));
Jason M. Billse855dd22019-10-08 11:37:48 -07002972}
2973
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002974inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002975{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002976 // Note: Deviated from redfish privilege registry for GET & HEAD
2977 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002978 /**
2979 * Functions triggers appropriate requests on DBus
2980 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002981 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07002982 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002983 // This is incorrect, should be.
2984 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002985 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002986 .methods(boost::beast::http::verb::get)(
2987 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07002988 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2989 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002990 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002991 {
2992 return;
2993 }
Ed Tanous22d268c2022-05-19 09:39:07 -07002994 if (systemName != "system")
2995 {
2996 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2997 systemName);
2998 return;
2999 }
3000
Ed Tanous002d39b2022-05-31 08:59:27 -07003001 crow::connections::systemBus->async_method_call(
3002 [asyncResp](const boost::system::error_code ec,
3003 const std::vector<std::string>& resp) {
3004 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003005 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003006 if (ec.value() !=
3007 boost::system::errc::no_such_file_or_directory)
3008 {
3009 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
3010 << ec.message();
3011 messages::internalError(asyncResp->res);
3012 return;
3013 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003014 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003015 asyncResp->res.jsonValue["@odata.type"] =
3016 "#LogEntryCollection.LogEntryCollection";
3017 asyncResp->res.jsonValue["@odata.id"] =
3018 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
3019 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
3020 asyncResp->res.jsonValue["Description"] =
3021 "Collection of Crashdump Entries";
3022 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3023 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08003024
Ed Tanous002d39b2022-05-31 08:59:27 -07003025 for (const std::string& path : resp)
3026 {
3027 const sdbusplus::message::object_path objPath(path);
3028 // Get the log ID
3029 std::string logID = objPath.filename();
3030 if (logID.empty())
3031 {
3032 continue;
3033 }
3034 // Add the log entry to the array
3035 logCrashdumpEntry(asyncResp, logID,
3036 asyncResp->res.jsonValue["Members"]);
3037 }
3038 },
3039 "xyz.openbmc_project.ObjectMapper",
3040 "/xyz/openbmc_project/object_mapper",
3041 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
3042 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003043 });
3044}
Ed Tanous1da66f72018-07-27 16:13:37 -07003045
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003046inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07003047{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003048 // Note: Deviated from redfish privilege registry for GET & HEAD
3049 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07003050
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003051 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003052 app, "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003053 // this is incorrect, should be
3054 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07003055 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003056 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003057 [&app](const crow::Request& req,
3058 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003059 const std::string& systemName, const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003060 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003061 {
3062 return;
3063 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003064 if (systemName != "system")
3065 {
3066 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3067 systemName);
3068 ;
3069 return;
3070 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003071 const std::string& logID = param;
3072 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
3073 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003074}
Ed Tanous1da66f72018-07-27 16:13:37 -07003075
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003076inline void requestRoutesCrashdumpFile(App& app)
3077{
3078 // Note: Deviated from redfish privilege registry for GET & HEAD
3079 // method for security reasons.
3080 BMCWEB_ROUTE(
3081 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003082 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003083 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003084 .methods(boost::beast::http::verb::get)(
Nan Zhoua4ce1142022-08-02 18:45:25 +00003085 [](const crow::Request& req,
3086 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003087 const std::string& systemName, const std::string& logID,
3088 const std::string& fileName) {
Shounak Mitra2a9beee2022-07-20 18:41:30 +00003089 // Do not call getRedfishRoute here since the crashdump file is not a
3090 // Redfish resource.
Ed Tanous22d268c2022-05-19 09:39:07 -07003091
3092 if (systemName != "system")
3093 {
3094 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3095 systemName);
3096 ;
3097 return;
3098 }
3099
Ed Tanous002d39b2022-05-31 08:59:27 -07003100 auto getStoredLogCallback =
3101 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
3102 const boost::system::error_code ec,
3103 const std::vector<
3104 std::pair<std::string, dbus::utility::DbusVariantType>>&
3105 resp) {
3106 if (ec)
3107 {
3108 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
3109 messages::internalError(asyncResp->res);
3110 return;
3111 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003112
Ed Tanous002d39b2022-05-31 08:59:27 -07003113 std::string dbusFilename{};
3114 std::string dbusTimestamp{};
3115 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003116
Ed Tanous002d39b2022-05-31 08:59:27 -07003117 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
3118 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003119
Ed Tanous002d39b2022-05-31 08:59:27 -07003120 if (dbusFilename.empty() || dbusTimestamp.empty() ||
3121 dbusFilepath.empty())
3122 {
3123 messages::resourceMissingAtURI(asyncResp->res, url);
3124 return;
3125 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003126
Ed Tanous002d39b2022-05-31 08:59:27 -07003127 // Verify the file name parameter is correct
3128 if (fileName != dbusFilename)
3129 {
3130 messages::resourceMissingAtURI(asyncResp->res, url);
3131 return;
3132 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003133
Ed Tanous002d39b2022-05-31 08:59:27 -07003134 if (!std::filesystem::exists(dbusFilepath))
3135 {
3136 messages::resourceMissingAtURI(asyncResp->res, url);
3137 return;
3138 }
3139 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
3140 asyncResp->res.body() =
3141 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003142
Ed Tanous002d39b2022-05-31 08:59:27 -07003143 // Configure this to be a file download when accessed
3144 // from a browser
Ed Tanousd9f6c622022-03-17 09:12:17 -07003145 asyncResp->res.addHeader(
3146 boost::beast::http::field::content_disposition, "attachment");
Ed Tanous002d39b2022-05-31 08:59:27 -07003147 };
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +02003148 sdbusplus::asio::getAllProperties(
3149 *crow::connections::systemBus, crashdumpObject,
3150 crashdumpPath + std::string("/") + logID, crashdumpInterface,
3151 std::move(getStoredLogCallback));
Ed Tanous002d39b2022-05-31 08:59:27 -07003152 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003153}
3154
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003155enum class OEMDiagnosticType
3156{
3157 onDemand,
3158 telemetry,
3159 invalid,
3160};
3161
Ed Tanousf7725d72022-03-07 12:46:00 -08003162inline OEMDiagnosticType
3163 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003164{
3165 if (oemDiagStr == "OnDemand")
3166 {
3167 return OEMDiagnosticType::onDemand;
3168 }
3169 if (oemDiagStr == "Telemetry")
3170 {
3171 return OEMDiagnosticType::telemetry;
3172 }
3173
3174 return OEMDiagnosticType::invalid;
3175}
3176
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003177inline void requestRoutesCrashdumpCollect(App& app)
3178{
3179 // Note: Deviated from redfish privilege registry for GET & HEAD
3180 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08003181 BMCWEB_ROUTE(
3182 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003183 "/redfish/v1/Systems/<str>/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07003184 // The below is incorrect; Should be ConfigureManager
3185 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003186 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07003187 .methods(boost::beast::http::verb::post)(
3188 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003189 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3190 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003191 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003192 {
3193 return;
3194 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003195
3196 if (systemName != "system")
3197 {
3198 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3199 systemName);
3200 ;
3201 return;
3202 }
3203
Ed Tanous002d39b2022-05-31 08:59:27 -07003204 std::string diagnosticDataType;
3205 std::string oemDiagnosticDataType;
3206 if (!redfish::json_util::readJsonAction(
3207 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3208 "OEMDiagnosticDataType", oemDiagnosticDataType))
3209 {
3210 return;
3211 }
3212
3213 if (diagnosticDataType != "OEM")
3214 {
3215 BMCWEB_LOG_ERROR
3216 << "Only OEM DiagnosticDataType supported for Crashdump";
3217 messages::actionParameterValueFormatError(
3218 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3219 "CollectDiagnosticData");
3220 return;
3221 }
3222
3223 OEMDiagnosticType oemDiagType =
3224 getOEMDiagnosticType(oemDiagnosticDataType);
3225
3226 std::string iface;
3227 std::string method;
3228 std::string taskMatchStr;
3229 if (oemDiagType == OEMDiagnosticType::onDemand)
3230 {
3231 iface = crashdumpOnDemandInterface;
3232 method = "GenerateOnDemandLog";
3233 taskMatchStr = "type='signal',"
3234 "interface='org.freedesktop.DBus.Properties',"
3235 "member='PropertiesChanged',"
3236 "arg0namespace='com.intel.crashdump'";
3237 }
3238 else if (oemDiagType == OEMDiagnosticType::telemetry)
3239 {
3240 iface = crashdumpTelemetryInterface;
3241 method = "GenerateTelemetryLog";
3242 taskMatchStr = "type='signal',"
3243 "interface='org.freedesktop.DBus.Properties',"
3244 "member='PropertiesChanged',"
3245 "arg0namespace='com.intel.crashdump'";
3246 }
3247 else
3248 {
3249 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3250 << oemDiagnosticDataType;
3251 messages::actionParameterValueFormatError(
3252 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3253 "CollectDiagnosticData");
3254 return;
3255 }
3256
3257 auto collectCrashdumpCallback =
3258 [asyncResp, payload(task::Payload(req)),
3259 taskMatchStr](const boost::system::error_code ec,
3260 const std::string&) mutable {
3261 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003262 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003263 if (ec.value() == boost::system::errc::operation_not_supported)
3264 {
3265 messages::resourceInStandby(asyncResp->res);
3266 }
3267 else if (ec.value() ==
3268 boost::system::errc::device_or_resource_busy)
3269 {
3270 messages::serviceTemporarilyUnavailable(asyncResp->res,
3271 "60");
3272 }
3273 else
3274 {
3275 messages::internalError(asyncResp->res);
3276 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003277 return;
3278 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003279 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Patrick Williams59d494e2022-07-22 19:26:55 -05003280 [](boost::system::error_code err, sdbusplus::message_t&,
Ed Tanous002d39b2022-05-31 08:59:27 -07003281 const std::shared_ptr<task::TaskData>& taskData) {
3282 if (!err)
3283 {
3284 taskData->messages.emplace_back(messages::taskCompletedOK(
3285 std::to_string(taskData->index)));
3286 taskData->state = "Completed";
3287 }
3288 return task::completed;
3289 },
3290 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003291
Ed Tanous002d39b2022-05-31 08:59:27 -07003292 task->startTimer(std::chrono::minutes(5));
3293 task->populateResp(asyncResp->res);
3294 task->payload.emplace(std::move(payload));
3295 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003296
Ed Tanous002d39b2022-05-31 08:59:27 -07003297 crow::connections::systemBus->async_method_call(
3298 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3299 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003300 });
3301}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003302
Andrew Geisslercb92c032018-08-17 07:56:14 -07003303/**
3304 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3305 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003306inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003307{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003308 /**
3309 * Function handles POST method request.
3310 * The Clear Log actions does not require any parameter.The action deletes
3311 * all entries found in the Entries collection for this Log Service.
3312 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003313
George Liu0fda0f12021-11-16 10:06:17 +08003314 BMCWEB_ROUTE(
3315 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003316 "/redfish/v1/Systems/<str>/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003317 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003318 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003319 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003320 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3321 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003322 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003323 {
3324 return;
3325 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003326 if (systemName != "system")
3327 {
3328 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3329 systemName);
3330 ;
3331 return;
3332 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003333 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003334
Ed Tanous002d39b2022-05-31 08:59:27 -07003335 // Process response from Logging service.
3336 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3337 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3338 if (ec)
3339 {
3340 // TODO Handle for specific error code
3341 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3342 asyncResp->res.result(
3343 boost::beast::http::status::internal_server_error);
3344 return;
3345 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003346
Ed Tanous002d39b2022-05-31 08:59:27 -07003347 asyncResp->res.result(boost::beast::http::status::no_content);
3348 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003349
Ed Tanous002d39b2022-05-31 08:59:27 -07003350 // Make call to Logging service to request Clear Log
3351 crow::connections::systemBus->async_method_call(
3352 respHandler, "xyz.openbmc_project.Logging",
3353 "/xyz/openbmc_project/logging",
3354 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3355 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003356}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003357
3358/****************************************************
3359 * Redfish PostCode interfaces
3360 * using DBUS interface: getPostCodesTS
3361 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003362inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003363{
Ed Tanous22d268c2022-05-19 09:39:07 -07003364 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003365 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003366 .methods(boost::beast::http::verb::get)(
3367 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003368 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3369 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003370 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003371 {
3372 return;
3373 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003374 if (systemName != "system")
3375 {
3376 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3377 systemName);
3378 ;
3379 return;
3380 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003381 asyncResp->res.jsonValue["@odata.id"] =
3382 "/redfish/v1/Systems/system/LogServices/PostCodes";
3383 asyncResp->res.jsonValue["@odata.type"] =
3384 "#LogService.v1_1_0.LogService";
3385 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3386 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3387 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3388 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3389 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3390 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303391
Ed Tanous002d39b2022-05-31 08:59:27 -07003392 std::pair<std::string, std::string> redfishDateTimeOffset =
Ed Tanous2b829372022-08-03 14:22:34 -07003393 redfish::time_utils::getDateTimeOffsetNow();
Ed Tanous002d39b2022-05-31 08:59:27 -07003394 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3395 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3396 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303397
Ed Tanous002d39b2022-05-31 08:59:27 -07003398 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3399 {"target",
3400 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003401 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003402}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003403
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003404inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003405{
George Liu0fda0f12021-11-16 10:06:17 +08003406 BMCWEB_ROUTE(
3407 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003408 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003409 // The following privilege is incorrect; It should be ConfigureManager
3410 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003411 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003412 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003413 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003414 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3415 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003416 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003417 {
3418 return;
3419 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003420 if (systemName != "system")
3421 {
3422 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3423 systemName);
3424 ;
3425 return;
3426 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003427 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003428
Ed Tanous002d39b2022-05-31 08:59:27 -07003429 // Make call to post-code service to request clear all
3430 crow::connections::systemBus->async_method_call(
3431 [asyncResp](const boost::system::error_code ec) {
3432 if (ec)
3433 {
3434 // TODO Handle for specific error code
3435 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3436 << ec;
3437 asyncResp->res.result(
3438 boost::beast::http::status::internal_server_error);
3439 messages::internalError(asyncResp->res);
3440 return;
3441 }
3442 },
3443 "xyz.openbmc_project.State.Boot.PostCode0",
3444 "/xyz/openbmc_project/State/Boot/PostCode0",
3445 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3446 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003447}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003448
3449static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003450 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303451 const boost::container::flat_map<
3452 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003453 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3454 const uint64_t skip = 0, const uint64_t top = 0)
3455{
3456 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003457 const registries::Message* message =
3458 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003459
3460 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003461 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003462
3463 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303464 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3465 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003466 {
3467 currentCodeIndex++;
3468 std::string postcodeEntryID =
3469 "B" + std::to_string(bootIndex) + "-" +
3470 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3471
3472 uint64_t usecSinceEpoch = code.first;
3473 uint64_t usTimeOffset = 0;
3474
3475 if (1 == currentCodeIndex)
3476 { // already incremented
3477 firstCodeTimeUs = code.first;
3478 }
3479 else
3480 {
3481 usTimeOffset = code.first - firstCodeTimeUs;
3482 }
3483
3484 // skip if no specific codeIndex is specified and currentCodeIndex does
3485 // not fall between top and skip
3486 if ((codeIndex == 0) &&
3487 (currentCodeIndex <= skip || currentCodeIndex > top))
3488 {
3489 continue;
3490 }
3491
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003492 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003493 // currentIndex
3494 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3495 {
3496 // This is done for simplicity. 1st entry is needed to calculate
3497 // time offset. To improve efficiency, one can get to the entry
3498 // directly (possibly with flatmap's nth method)
3499 continue;
3500 }
3501
3502 // currentCodeIndex is within top and skip or equal to specified code
3503 // index
3504
3505 // Get the Created time from the timestamp
3506 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003507 entryTimeStr =
Ed Tanous2b829372022-08-03 14:22:34 -07003508 redfish::time_utils::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003509
3510 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3511 std::ostringstream hexCode;
3512 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303513 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003514 std::ostringstream timeOffsetStr;
3515 // Set Fixed -Point Notation
3516 timeOffsetStr << std::fixed;
3517 // Set precision to 4 digits
3518 timeOffsetStr << std::setprecision(4);
3519 // Add double to stream
3520 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3521 std::vector<std::string> messageArgs = {
3522 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3523
3524 // Get MessageArgs template from message registry
3525 std::string msg;
3526 if (message != nullptr)
3527 {
3528 msg = message->message;
3529
3530 // fill in this post code value
3531 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003532 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003533 {
3534 std::string argStr = "%" + std::to_string(++i);
3535 size_t argPos = msg.find(argStr);
3536 if (argPos != std::string::npos)
3537 {
3538 msg.replace(argPos, argStr.length(), messageArg);
3539 }
3540 }
3541 }
3542
Tim Leed4342a92020-04-27 11:47:58 +08003543 // Get Severity template from message registry
3544 std::string severity;
3545 if (message != nullptr)
3546 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003547 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003548 }
3549
ZhikuiRena3316fc2020-01-29 14:58:08 -08003550 // add to AsyncResp
3551 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003552 nlohmann::json& bmcLogEntry = logEntryArray.back();
Vijay Lobo9c11a172021-10-07 16:53:16 -05003553 bmcLogEntry["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Jason M. Bills84afc482022-06-24 12:38:23 -07003554 bmcLogEntry["@odata.id"] =
3555 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3556 postcodeEntryID;
3557 bmcLogEntry["Name"] = "POST Code Log Entry";
3558 bmcLogEntry["Id"] = postcodeEntryID;
3559 bmcLogEntry["Message"] = std::move(msg);
3560 bmcLogEntry["MessageId"] = "OpenBMC.0.2.BIOSPOSTCode";
3561 bmcLogEntry["MessageArgs"] = std::move(messageArgs);
3562 bmcLogEntry["EntryType"] = "Event";
3563 bmcLogEntry["Severity"] = std::move(severity);
3564 bmcLogEntry["Created"] = entryTimeStr;
George Liu647b3cd2021-07-05 12:43:56 +08003565 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3566 {
3567 bmcLogEntry["AdditionalDataURI"] =
3568 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3569 postcodeEntryID + "/attachment";
3570 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003571 }
3572}
3573
zhanghch058d1b46d2021-04-01 11:18:24 +08003574static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003575 const uint16_t bootIndex,
3576 const uint64_t codeIndex)
3577{
3578 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303579 [aResp, bootIndex,
3580 codeIndex](const boost::system::error_code ec,
3581 const boost::container::flat_map<
3582 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3583 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003584 if (ec)
3585 {
3586 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3587 messages::internalError(aResp->res);
3588 return;
3589 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003590
Ed Tanous002d39b2022-05-31 08:59:27 -07003591 // skip the empty postcode boots
3592 if (postcode.empty())
3593 {
3594 return;
3595 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003596
Ed Tanous002d39b2022-05-31 08:59:27 -07003597 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003598
Ed Tanous002d39b2022-05-31 08:59:27 -07003599 aResp->res.jsonValue["Members@odata.count"] =
3600 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003601 },
Jonathan Doman15124762021-01-07 17:54:17 -08003602 "xyz.openbmc_project.State.Boot.PostCode0",
3603 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003604 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3605 bootIndex);
3606}
3607
zhanghch058d1b46d2021-04-01 11:18:24 +08003608static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003609 const uint16_t bootIndex,
3610 const uint16_t bootCount,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003611 const uint64_t entryCount, size_t skip,
3612 size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003613{
3614 crow::connections::systemBus->async_method_call(
3615 [aResp, bootIndex, bootCount, entryCount, skip,
3616 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303617 const boost::container::flat_map<
3618 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3619 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003620 if (ec)
3621 {
3622 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3623 messages::internalError(aResp->res);
3624 return;
3625 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003626
Ed Tanous002d39b2022-05-31 08:59:27 -07003627 uint64_t endCount = entryCount;
3628 if (!postcode.empty())
3629 {
3630 endCount = entryCount + postcode.size();
Ed Tanous3648c8b2022-07-25 13:39:59 -07003631 if (skip < endCount && (top + skip) > entryCount)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003632 {
Ed Tanous3648c8b2022-07-25 13:39:59 -07003633 uint64_t thisBootSkip =
3634 std::max(static_cast<uint64_t>(skip), entryCount) -
3635 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003636 uint64_t thisBootTop =
Ed Tanous3648c8b2022-07-25 13:39:59 -07003637 std::min(static_cast<uint64_t>(top + skip), endCount) -
3638 entryCount;
Ed Tanous002d39b2022-05-31 08:59:27 -07003639
3640 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3641 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003642 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003643 aResp->res.jsonValue["Members@odata.count"] = endCount;
3644 }
3645
3646 // continue to previous bootIndex
3647 if (bootIndex < bootCount)
3648 {
3649 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3650 bootCount, endCount, skip, top);
3651 }
Jiaqing Zhao81584ab2022-07-28 00:33:45 +08003652 else if (skip + top < endCount)
Ed Tanous002d39b2022-05-31 08:59:27 -07003653 {
3654 aResp->res.jsonValue["Members@odata.nextLink"] =
3655 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3656 std::to_string(skip + top);
3657 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003658 },
Jonathan Doman15124762021-01-07 17:54:17 -08003659 "xyz.openbmc_project.State.Boot.PostCode0",
3660 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003661 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3662 bootIndex);
3663}
3664
zhanghch058d1b46d2021-04-01 11:18:24 +08003665static void
3666 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Ed Tanous3648c8b2022-07-25 13:39:59 -07003667 size_t skip, size_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003668{
3669 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003670 sdbusplus::asio::getProperty<uint16_t>(
3671 *crow::connections::systemBus,
3672 "xyz.openbmc_project.State.Boot.PostCode0",
3673 "/xyz/openbmc_project/State/Boot/PostCode0",
3674 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3675 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3676 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003677 if (ec)
3678 {
3679 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3680 messages::internalError(aResp->res);
3681 return;
3682 }
3683 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003684 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003685}
3686
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003687inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003688{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003689 BMCWEB_ROUTE(app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003690 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003691 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003692 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003693 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -07003694 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3695 const std::string& systemName) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003696 query_param::QueryCapabilities capabilities = {
3697 .canDelegateTop = true,
3698 .canDelegateSkip = true,
3699 };
3700 query_param::Query delegatedQuery;
3701 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003702 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003703 {
3704 return;
3705 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003706
3707 if (systemName != "system")
3708 {
3709 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3710 systemName);
3711 ;
3712 return;
3713 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003714 asyncResp->res.jsonValue["@odata.type"] =
3715 "#LogEntryCollection.LogEntryCollection";
3716 asyncResp->res.jsonValue["@odata.id"] =
3717 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3718 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3719 asyncResp->res.jsonValue["Description"] =
3720 "Collection of POST Code Log Entries";
3721 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3722 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous3648c8b2022-07-25 13:39:59 -07003723 size_t skip = delegatedQuery.skip.value_or(0);
Jiaqing Zhao5143f7a2022-07-22 09:33:33 +08003724 size_t top = delegatedQuery.top.value_or(query_param::Query::maxTop);
Ed Tanous3648c8b2022-07-25 13:39:59 -07003725 getCurrentBootNumber(asyncResp, skip, top);
Ed Tanous002d39b2022-05-31 08:59:27 -07003726 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003727}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003728
George Liu647b3cd2021-07-05 12:43:56 +08003729/**
3730 * @brief Parse post code ID and get the current value and index value
3731 * eg: postCodeID=B1-2, currentValue=1, index=2
3732 *
3733 * @param[in] postCodeID Post Code ID
3734 * @param[out] currentValue Current value
3735 * @param[out] index Index value
3736 *
3737 * @return bool true if the parsing is successful, false the parsing fails
3738 */
3739inline static bool parsePostCode(const std::string& postCodeID,
3740 uint64_t& currentValue, uint16_t& index)
3741{
3742 std::vector<std::string> split;
3743 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3744 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3745 {
3746 return false;
3747 }
3748
Ed Tanousca45aa32022-01-07 09:28:45 -08003749 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003750 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003751 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003752 const char* end = split[0].data() + split[0].size();
3753 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3754
3755 if (ptrIndex != end || ecIndex != std::errc())
3756 {
3757 return false;
3758 }
3759
3760 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003761
3762 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003763 end = split[1].data() + split[1].size();
3764 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003765
Tony Lee517d9a52022-06-28 15:41:23 +08003766 return ptrValue == end && ecValue == std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003767}
3768
3769inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3770{
George Liu0fda0f12021-11-16 10:06:17 +08003771 BMCWEB_ROUTE(
3772 app,
Ed Tanous22d268c2022-05-19 09:39:07 -07003773 "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003774 .privileges(redfish::privileges::getLogEntry)
3775 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003776 [&app](const crow::Request& req,
3777 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003778 const std::string& systemName,
Ed Tanous45ca1b82022-03-25 13:07:27 -07003779 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003780 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003781 {
3782 return;
3783 }
Ed Tanous99351cd2022-08-07 16:42:51 -07003784 if (http_helpers::isContentTypeAllowed(
3785 req.getHeaderValue("Accept"),
Ed Tanous4a0e1a02022-09-21 15:28:04 -07003786 http_helpers::ContentType::OctetStream, true))
Ed Tanous002d39b2022-05-31 08:59:27 -07003787 {
3788 asyncResp->res.result(boost::beast::http::status::bad_request);
3789 return;
3790 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003791 if (systemName != "system")
3792 {
3793 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3794 systemName);
3795 ;
3796 return;
3797 }
George Liu647b3cd2021-07-05 12:43:56 +08003798
Ed Tanous002d39b2022-05-31 08:59:27 -07003799 uint64_t currentValue = 0;
3800 uint16_t index = 0;
3801 if (!parsePostCode(postCodeID, currentValue, index))
3802 {
3803 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3804 return;
3805 }
George Liu647b3cd2021-07-05 12:43:56 +08003806
Ed Tanous002d39b2022-05-31 08:59:27 -07003807 crow::connections::systemBus->async_method_call(
3808 [asyncResp, postCodeID, currentValue](
3809 const boost::system::error_code ec,
3810 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3811 postcodes) {
3812 if (ec.value() == EBADR)
3813 {
3814 messages::resourceNotFound(asyncResp->res, "LogEntry",
3815 postCodeID);
3816 return;
3817 }
3818 if (ec)
3819 {
3820 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3821 messages::internalError(asyncResp->res);
3822 return;
3823 }
George Liu647b3cd2021-07-05 12:43:56 +08003824
Ed Tanous002d39b2022-05-31 08:59:27 -07003825 size_t value = static_cast<size_t>(currentValue) - 1;
3826 if (value == std::string::npos || postcodes.size() < currentValue)
3827 {
3828 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3829 messages::resourceNotFound(asyncResp->res, "LogEntry",
3830 postCodeID);
3831 return;
3832 }
George Liu647b3cd2021-07-05 12:43:56 +08003833
Ed Tanous002d39b2022-05-31 08:59:27 -07003834 const auto& [tID, c] = postcodes[value];
3835 if (c.empty())
3836 {
3837 BMCWEB_LOG_INFO << "No found post code data";
3838 messages::resourceNotFound(asyncResp->res, "LogEntry",
3839 postCodeID);
3840 return;
3841 }
3842 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3843 const char* d = reinterpret_cast<const char*>(c.data());
3844 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003845
Ed Tanousd9f6c622022-03-17 09:12:17 -07003846 asyncResp->res.addHeader(boost::beast::http::field::content_type,
Ed Tanous002d39b2022-05-31 08:59:27 -07003847 "application/octet-stream");
Ed Tanousd9f6c622022-03-17 09:12:17 -07003848 asyncResp->res.addHeader(
3849 boost::beast::http::field::content_transfer_encoding, "Base64");
Ed Tanous002d39b2022-05-31 08:59:27 -07003850 asyncResp->res.body() = crow::utility::base64encode(strData);
3851 },
3852 "xyz.openbmc_project.State.Boot.PostCode0",
3853 "/xyz/openbmc_project/State/Boot/PostCode0",
3854 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3855 });
George Liu647b3cd2021-07-05 12:43:56 +08003856}
3857
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003858inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003859{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003860 BMCWEB_ROUTE(
Ed Tanous22d268c2022-05-19 09:39:07 -07003861 app, "/redfish/v1/Systems/<str>/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003862 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003863 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003864 [&app](const crow::Request& req,
3865 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -07003866 const std::string& systemName, const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003867 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003868 {
3869 return;
3870 }
Ed Tanous22d268c2022-05-19 09:39:07 -07003871 if (systemName != "system")
3872 {
3873 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3874 systemName);
3875 return;
3876 }
3877
Ed Tanous002d39b2022-05-31 08:59:27 -07003878 uint16_t bootIndex = 0;
3879 uint64_t codeIndex = 0;
3880 if (!parsePostCode(targetID, codeIndex, bootIndex))
3881 {
3882 // Requested ID was not found
3883 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
3884 return;
3885 }
3886 if (bootIndex == 0 || codeIndex == 0)
3887 {
3888 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3889 << targetID;
3890 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003891
Vijay Lobo9c11a172021-10-07 16:53:16 -05003892 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_9_0.LogEntry";
Ed Tanous002d39b2022-05-31 08:59:27 -07003893 asyncResp->res.jsonValue["@odata.id"] =
3894 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3895 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3896 asyncResp->res.jsonValue["Description"] =
3897 "Collection of POST Code Log Entries";
3898 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3899 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003900
Ed Tanous002d39b2022-05-31 08:59:27 -07003901 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3902 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003903}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003904
Ed Tanous1da66f72018-07-27 16:13:37 -07003905} // namespace redfish