blob: 3a8ce1090038dc46c2e78e9c24bac6f3ef584a11 [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>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060030#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070031#include <boost/algorithm/string/split.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060032#include <boost/beast/http.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070033#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080034#include <boost/system/linux_error.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080035#include <dbus_utility.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070036#include <error_messages.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070037#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070038#include <registries/privilege_registry.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039
George Liu647b3cd2021-07-05 12:43:56 +080040#include <charconv>
James Feist4418c7f2019-04-15 11:09:15 -070041#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080042#include <optional>
Ed Tanous26702d02021-11-03 15:02:33 -070043#include <span>
Jason M. Billscd225da2019-05-08 15:31:57 -070044#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080045#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070046
47namespace redfish
48{
49
Gunnar Mills1214b7e2020-06-04 10:11:30 -050050constexpr char const* crashdumpObject = "com.intel.crashdump";
51constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050052constexpr char const* crashdumpInterface = "com.intel.crashdump";
53constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070054 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050055constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070056 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070057constexpr char const* crashdumpTelemetryInterface =
58 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070059
Ed Tanousfffb8c12022-02-07 23:53:03 -080060namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -070061{
Ed Tanous26702d02021-11-03 15:02:33 -070062static const Message*
63 getMessageFromRegistry(const std::string& messageKey,
64 const std::span<const MessageEntry> registry)
Jason M. Bills4851d452019-03-28 11:27:48 -070065{
Ed Tanous26702d02021-11-03 15:02:33 -070066 std::span<const MessageEntry>::iterator messageIt = std::find_if(
67 registry.begin(), registry.end(),
68 [&messageKey](const MessageEntry& messageEntry) {
Ed Tanouse662eae2022-01-25 10:39:19 -080069 return std::strcmp(messageEntry.first, messageKey.c_str()) == 0;
Ed Tanous26702d02021-11-03 15:02:33 -070070 });
71 if (messageIt != registry.end())
Jason M. Bills4851d452019-03-28 11:27:48 -070072 {
73 return &messageIt->second;
74 }
75
76 return nullptr;
77}
78
Gunnar Mills1214b7e2020-06-04 10:11:30 -050079static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070080{
81 // Redfish MessageIds are in the form
82 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
83 // the right Message
84 std::vector<std::string> fields;
85 fields.reserve(4);
86 boost::split(fields, messageID, boost::is_any_of("."));
Gunnar Mills1214b7e2020-06-04 10:11:30 -050087 std::string& registryName = fields[0];
88 std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070089
90 // Find the right registry and check it for the MessageKey
91 if (std::string(base::header.registryPrefix) == registryName)
92 {
93 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070094 messageKey, std::span<const MessageEntry>(base::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -070095 }
96 if (std::string(openbmc::header.registryPrefix) == registryName)
97 {
98 return getMessageFromRegistry(
Ed Tanous26702d02021-11-03 15:02:33 -070099 messageKey, std::span<const MessageEntry>(openbmc::registry));
Jason M. Bills4851d452019-03-28 11:27:48 -0700100 }
101 return nullptr;
102}
Ed Tanousfffb8c12022-02-07 23:53:03 -0800103} // namespace registries
Jason M. Bills4851d452019-03-28 11:27:48 -0700104
James Feistf6150402019-01-08 10:36:20 -0800105namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700106
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500107inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700108{
Ed Tanousd4d25792020-09-29 15:15:03 -0700109 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
110 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
111 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
112 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700113 {
114 return "Critical";
115 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700116 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
117 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
118 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700119 {
120 return "OK";
121 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700122 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700123 {
124 return "Warning";
125 }
126 return "";
127}
128
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700129inline static int getJournalMetadata(sd_journal* journal,
130 const std::string_view& field,
131 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700132{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500133 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700134 size_t length = 0;
135 int ret = 0;
136 // Get the metadata from the requested field of the journal entry
Ed Tanous46ff87b2022-01-07 09:25:51 -0800137 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
138 const void** dataVoid = reinterpret_cast<const void**>(&data);
139
140 ret = sd_journal_get_data(journal, field.data(), dataVoid, &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700141 if (ret < 0)
142 {
143 return ret;
144 }
Ed Tanous39e77502019-03-04 17:35:53 -0800145 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700146 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000147 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700148 return ret;
149}
150
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700151inline static int getJournalMetadata(sd_journal* journal,
152 const std::string_view& field,
153 const int& base, long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700154{
155 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800156 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700157 // Get the metadata from the requested field of the journal entry
158 ret = getJournalMetadata(journal, field, metadata);
159 if (ret < 0)
160 {
161 return ret;
162 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000163 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700164 return ret;
165}
166
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167inline static bool getEntryTimestamp(sd_journal* journal,
168 std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800169{
170 int ret = 0;
171 uint64_t timestamp = 0;
172 ret = sd_journal_get_realtime_usec(journal, &timestamp);
173 if (ret < 0)
174 {
175 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
176 << strerror(-ret);
177 return false;
178 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800179 entryTimestamp = crow::utility::getDateTimeUint(timestamp / 1000 / 1000);
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500180 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800181}
Ed Tanous50b8a432022-02-03 16:29:50 -0800182
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700183inline static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
184 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700185{
186 int ret = 0;
187 static uint64_t prevTs = 0;
188 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700189 if (firstEntry)
190 {
191 prevTs = 0;
192 }
193
Jason M. Bills16428a12018-11-02 12:42:29 -0700194 // Get the entry timestamp
195 uint64_t curTs = 0;
196 ret = sd_journal_get_realtime_usec(journal, &curTs);
197 if (ret < 0)
198 {
199 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
200 << strerror(-ret);
201 return false;
202 }
203 // If the timestamp isn't unique, increment the index
204 if (curTs == prevTs)
205 {
206 index++;
207 }
208 else
209 {
210 // Otherwise, reset it
211 index = 0;
212 }
213 // Save the timestamp
214 prevTs = curTs;
215
216 entryID = std::to_string(curTs);
217 if (index > 0)
218 {
219 entryID += "_" + std::to_string(index);
220 }
221 return true;
222}
223
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500224static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700225 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700226{
Ed Tanous271584a2019-07-09 16:24:22 -0700227 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700228 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700229 if (firstEntry)
230 {
231 prevTs = 0;
232 }
233
Jason M. Bills95820182019-04-22 16:25:34 -0700234 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700235 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700236 std::tm timeStruct = {};
237 std::istringstream entryStream(logEntry);
238 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
239 {
240 curTs = std::mktime(&timeStruct);
241 }
242 // If the timestamp isn't unique, increment the index
243 if (curTs == prevTs)
244 {
245 index++;
246 }
247 else
248 {
249 // Otherwise, reset it
250 index = 0;
251 }
252 // Save the timestamp
253 prevTs = curTs;
254
255 entryID = std::to_string(curTs);
256 if (index > 0)
257 {
258 entryID += "_" + std::to_string(index);
259 }
260 return true;
261}
262
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700263inline static bool
zhanghch058d1b46d2021-04-01 11:18:24 +0800264 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
265 const std::string& entryID, uint64_t& timestamp,
266 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700267{
268 if (entryID.empty())
269 {
270 return false;
271 }
272 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800273 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700274
Ed Tanous81ce6092020-12-17 16:54:55 +0000275 auto underscorePos = tsStr.find('_');
Ed Tanous71d5d8d2022-01-25 11:04:33 -0800276 if (underscorePos != std::string_view::npos)
Jason M. Bills16428a12018-11-02 12:42:29 -0700277 {
278 // Timestamp has an index
279 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800280 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700281 indexStr.remove_prefix(underscorePos + 1);
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700282 auto [ptr, ec] = std::from_chars(
283 indexStr.data(), indexStr.data() + indexStr.size(), index);
284 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700285 {
Ed Tanousace85d62021-10-26 12:45:59 -0700286 messages::resourceMissingAtURI(
287 asyncResp->res, crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700288 return false;
289 }
290 }
291 // Timestamp has no index
Ed Tanousc0bd5e42021-09-13 17:00:19 -0700292 auto [ptr, ec] =
293 std::from_chars(tsStr.data(), tsStr.data() + tsStr.size(), timestamp);
294 if (ec != std::errc())
Jason M. Bills16428a12018-11-02 12:42:29 -0700295 {
Ed Tanousace85d62021-10-26 12:45:59 -0700296 messages::resourceMissingAtURI(asyncResp->res,
297 crow::utility::urlFromPieces(entryID));
Jason M. Bills16428a12018-11-02 12:42:29 -0700298 return false;
299 }
300 return true;
301}
302
Jason M. Bills95820182019-04-22 16:25:34 -0700303static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500304 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700305{
306 static const std::filesystem::path redfishLogDir = "/var/log";
307 static const std::string redfishLogFilename = "redfish";
308
309 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500310 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700311 std::filesystem::directory_iterator(redfishLogDir))
312 {
313 // If we find a redfish log file, save the path
314 std::string filename = dirEnt.path().filename();
315 if (boost::starts_with(filename, redfishLogFilename))
316 {
317 redfishLogFiles.emplace_back(redfishLogDir / filename);
318 }
319 }
320 // As the log files rotate, they are appended with a ".#" that is higher for
321 // the older logs. Since we don't expect more than 10 log files, we
322 // can just sort the list to get them in order from newest to oldest
323 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
324
325 return !redfishLogFiles.empty();
326}
327
zhanghch058d1b46d2021-04-01 11:18:24 +0800328inline void
329 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
330 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500331{
332 std::string dumpPath;
333 if (dumpType == "BMC")
334 {
335 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
336 }
337 else if (dumpType == "System")
338 {
339 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
340 }
341 else
342 {
343 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
344 messages::internalError(asyncResp->res);
345 return;
346 }
347
348 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800349 [asyncResp, dumpPath,
350 dumpType](const boost::system::error_code ec,
351 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500352 if (ec)
353 {
354 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
355 messages::internalError(asyncResp->res);
356 return;
357 }
358
359 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
360 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500361 std::string dumpEntryPath =
362 "/xyz/openbmc_project/dump/" +
363 std::string(boost::algorithm::to_lower_copy(dumpType)) +
364 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500365
366 for (auto& object : resp)
367 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500368 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500369 {
370 continue;
371 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800372 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500373 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500374 std::string dumpStatus;
375 nlohmann::json thisEntry;
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000376
377 std::string entryID = object.first.filename();
378 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500379 {
380 continue;
381 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500382
383 for (auto& interfaceMap : object.second)
384 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500385 if (interfaceMap.first ==
386 "xyz.openbmc_project.Common.Progress")
387 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800388 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500389 {
390 if (propertyMap.first == "Status")
391 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800392 const auto* status = std::get_if<std::string>(
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500393 &propertyMap.second);
394 if (status == nullptr)
395 {
396 messages::internalError(asyncResp->res);
397 break;
398 }
399 dumpStatus = *status;
400 }
401 }
402 }
403 else if (interfaceMap.first ==
404 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500405 {
406
407 for (auto& propertyMap : interfaceMap.second)
408 {
409 if (propertyMap.first == "Size")
410 {
Ed Tanous55f79e62022-01-25 11:26:16 -0800411 const auto* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500412 std::get_if<uint64_t>(&propertyMap.second);
413 if (sizePtr == nullptr)
414 {
415 messages::internalError(asyncResp->res);
416 break;
417 }
418 size = *sizePtr;
419 break;
420 }
421 }
422 }
423 else if (interfaceMap.first ==
424 "xyz.openbmc_project.Time.EpochTime")
425 {
426
Ed Tanous9eb808c2022-01-25 10:19:23 -0800427 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500428 {
429 if (propertyMap.first == "Elapsed")
430 {
431 const uint64_t* usecsTimeStamp =
432 std::get_if<uint64_t>(&propertyMap.second);
433 if (usecsTimeStamp == nullptr)
434 {
435 messages::internalError(asyncResp->res);
436 break;
437 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800438 timestamp = (*usecsTimeStamp / 1000 / 1000);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500439 break;
440 }
441 }
442 }
443 }
444
George Liu0fda0f12021-11-16 10:06:17 +0800445 if (dumpStatus !=
446 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500447 !dumpStatus.empty())
448 {
449 // Dump status is not Complete, no need to enumerate
450 continue;
451 }
452
George Liu647b3cd2021-07-05 12:43:56 +0800453 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500454 thisEntry["@odata.id"] = dumpPath + entryID;
455 thisEntry["Id"] = entryID;
456 thisEntry["EntryType"] = "Event";
Nan Zhou1d8782e2021-11-29 22:23:18 -0800457 thisEntry["Created"] =
458 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500459 thisEntry["Name"] = dumpType + " Dump Entry";
460
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500461 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500462
463 if (dumpType == "BMC")
464 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500465 thisEntry["DiagnosticDataType"] = "Manager";
466 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500467 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
468 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500469 }
470 else if (dumpType == "System")
471 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500472 thisEntry["DiagnosticDataType"] = "OEM";
473 thisEntry["OEMDiagnosticDataType"] = "System";
474 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500475 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
476 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500477 }
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500478 entriesArray.push_back(std::move(thisEntry));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500479 }
480 asyncResp->res.jsonValue["Members@odata.count"] =
481 entriesArray.size();
482 },
483 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
484 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
485}
486
zhanghch058d1b46d2021-04-01 11:18:24 +0800487inline void
Ed Tanous45ca1b82022-03-25 13:07:27 -0700488 getDumpEntryById(crow::App& app, const crow::Request& req,
489 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800490 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500491{
Ed Tanous45ca1b82022-03-25 13:07:27 -0700492 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
493 {
494 return;
495 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500496 std::string dumpPath;
497 if (dumpType == "BMC")
498 {
499 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
500 }
501 else if (dumpType == "System")
502 {
503 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
504 }
505 else
506 {
507 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
508 messages::internalError(asyncResp->res);
509 return;
510 }
511
512 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800513 [asyncResp, entryID, dumpPath,
514 dumpType](const boost::system::error_code ec,
515 dbus::utility::ManagedObjectType& resp) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500516 if (ec)
517 {
518 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
519 messages::internalError(asyncResp->res);
520 return;
521 }
522
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500523 bool foundDumpEntry = false;
524 std::string dumpEntryPath =
525 "/xyz/openbmc_project/dump/" +
526 std::string(boost::algorithm::to_lower_copy(dumpType)) +
527 "/entry/";
528
Ed Tanous9eb808c2022-01-25 10:19:23 -0800529 for (const auto& objectPath : resp)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500530 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500531 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500532 {
533 continue;
534 }
535
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500536 foundDumpEntry = true;
Nan Zhou1d8782e2021-11-29 22:23:18 -0800537 uint64_t timestamp = 0;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500538 uint64_t size = 0;
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500539 std::string dumpStatus;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500540
Ed Tanous9eb808c2022-01-25 10:19:23 -0800541 for (const auto& interfaceMap : objectPath.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500542 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500543 if (interfaceMap.first ==
544 "xyz.openbmc_project.Common.Progress")
545 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800546 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500547 {
548 if (propertyMap.first == "Status")
549 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800550 const std::string* status =
551 std::get_if<std::string>(
552 &propertyMap.second);
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500553 if (status == nullptr)
554 {
555 messages::internalError(asyncResp->res);
556 break;
557 }
558 dumpStatus = *status;
559 }
560 }
561 }
562 else if (interfaceMap.first ==
563 "xyz.openbmc_project.Dump.Entry")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500564 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800565 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500566 {
567 if (propertyMap.first == "Size")
568 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800569 const uint64_t* sizePtr =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500570 std::get_if<uint64_t>(&propertyMap.second);
571 if (sizePtr == nullptr)
572 {
573 messages::internalError(asyncResp->res);
574 break;
575 }
576 size = *sizePtr;
577 break;
578 }
579 }
580 }
581 else if (interfaceMap.first ==
582 "xyz.openbmc_project.Time.EpochTime")
583 {
Ed Tanous9eb808c2022-01-25 10:19:23 -0800584 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500585 {
586 if (propertyMap.first == "Elapsed")
587 {
588 const uint64_t* usecsTimeStamp =
589 std::get_if<uint64_t>(&propertyMap.second);
590 if (usecsTimeStamp == nullptr)
591 {
592 messages::internalError(asyncResp->res);
593 break;
594 }
Nan Zhou1d8782e2021-11-29 22:23:18 -0800595 timestamp = *usecsTimeStamp / 1000 / 1000;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500596 break;
597 }
598 }
599 }
600 }
601
George Liu0fda0f12021-11-16 10:06:17 +0800602 if (dumpStatus !=
603 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500604 !dumpStatus.empty())
605 {
606 // Dump status is not Complete
607 // return not found until status is changed to Completed
608 messages::resourceNotFound(asyncResp->res,
609 dumpType + " dump", entryID);
610 return;
611 }
612
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500613 asyncResp->res.jsonValue["@odata.type"] =
George Liu647b3cd2021-07-05 12:43:56 +0800614 "#LogEntry.v1_8_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500615 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
616 asyncResp->res.jsonValue["Id"] = entryID;
617 asyncResp->res.jsonValue["EntryType"] = "Event";
618 asyncResp->res.jsonValue["Created"] =
Nan Zhou1d8782e2021-11-29 22:23:18 -0800619 crow::utility::getDateTimeUint(timestamp);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500620 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
621
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500622 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500623
624 if (dumpType == "BMC")
625 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500626 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
627 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500628 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
629 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500630 }
631 else if (dumpType == "System")
632 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500633 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
634 asyncResp->res.jsonValue["OEMDiagnosticDataType"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500635 "System";
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500636 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500637 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
638 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 }
640 }
Ed Tanouse05aec52022-01-25 10:28:56 -0800641 if (!foundDumpEntry)
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500642 {
643 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
644 messages::internalError(asyncResp->res);
645 return;
646 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500647 },
648 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
649 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
650}
651
zhanghch058d1b46d2021-04-01 11:18:24 +0800652inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800653 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500654 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500655{
George Liu3de8d8b2021-03-22 17:49:39 +0800656 auto respHandler = [asyncResp,
657 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500658 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
659 if (ec)
660 {
George Liu3de8d8b2021-03-22 17:49:39 +0800661 if (ec.value() == EBADR)
662 {
663 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
664 return;
665 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500666 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
667 << ec;
668 messages::internalError(asyncResp->res);
669 return;
670 }
671 };
672 crow::connections::systemBus->async_method_call(
673 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500674 "/xyz/openbmc_project/dump/" +
675 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
676 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500677 "xyz.openbmc_project.Object.Delete", "Delete");
678}
679
zhanghch058d1b46d2021-04-01 11:18:24 +0800680inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700681 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800682 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
683 const uint32_t& dumpId, const std::string& dumpPath,
684 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500685{
686 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500687 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500688 boost::system::error_code err, sdbusplus::message::message& m,
689 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000690 if (err)
691 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500692 BMCWEB_LOG_ERROR << "Error in creating a dump";
693 taskData->state = "Cancelled";
694 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000695 }
Ed Tanousb9d36b42022-02-26 21:42:46 -0800696
697 dbus::utility::DBusInteracesMap interfacesList;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500698
699 sdbusplus::message::object_path objPath;
700
701 m.read(objPath, interfacesList);
702
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500703 if (objPath.str ==
704 "/xyz/openbmc_project/dump/" +
705 std::string(boost::algorithm::to_lower_copy(dumpType)) +
706 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500707 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500708 nlohmann::json retMessage = messages::success();
709 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500710
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500711 std::string headerLoc =
712 "Location: " + dumpPath + std::to_string(dumpId);
713 taskData->payload->httpHeaders.emplace_back(
714 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500715
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500716 taskData->state = "Completed";
717 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500718 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500719 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500720 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800721 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500722 "member='InterfacesAdded', "
723 "path='/xyz/openbmc_project/dump'");
724
725 task->startTimer(std::chrono::minutes(3));
726 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700727 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500728}
729
zhanghch058d1b46d2021-04-01 11:18:24 +0800730inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
731 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500732{
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500733 std::string dumpPath;
734 if (dumpType == "BMC")
735 {
736 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
737 }
738 else if (dumpType == "System")
739 {
740 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
741 }
742 else
743 {
744 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
745 messages::internalError(asyncResp->res);
746 return;
747 }
748
749 std::optional<std::string> diagnosticDataType;
750 std::optional<std::string> oemDiagnosticDataType;
751
Willy Tu15ed6782021-12-14 11:03:16 -0800752 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500753 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
754 "OEMDiagnosticDataType", oemDiagnosticDataType))
755 {
756 return;
757 }
758
759 if (dumpType == "System")
760 {
761 if (!oemDiagnosticDataType || !diagnosticDataType)
762 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800763 BMCWEB_LOG_ERROR
764 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500765 messages::actionParameterMissing(
766 asyncResp->res, "CollectDiagnosticData",
767 "DiagnosticDataType & OEMDiagnosticDataType");
768 return;
769 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700770 if ((*oemDiagnosticDataType != "System") ||
771 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500772 {
773 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700774 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500775 return;
776 }
777 }
778 else if (dumpType == "BMC")
779 {
780 if (!diagnosticDataType)
781 {
George Liu0fda0f12021-11-16 10:06:17 +0800782 BMCWEB_LOG_ERROR
783 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500784 messages::actionParameterMissing(
785 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
786 return;
787 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700788 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500789 {
790 BMCWEB_LOG_ERROR
791 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700792 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500793 return;
794 }
795 }
796
797 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700798 [asyncResp, payload(task::Payload(req)), dumpPath,
799 dumpType](const boost::system::error_code ec,
800 const uint32_t& dumpId) mutable {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500801 if (ec)
802 {
803 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
804 messages::internalError(asyncResp->res);
805 return;
806 }
807 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
808
Ed Tanous98be3e32021-09-16 15:05:36 -0700809 createDumpTaskCallback(std::move(payload), asyncResp, dumpId,
810 dumpPath, dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500811 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500812 "xyz.openbmc_project.Dump.Manager",
813 "/xyz/openbmc_project/dump/" +
814 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500815 "xyz.openbmc_project.Dump.Create", "CreateDump");
816}
817
zhanghch058d1b46d2021-04-01 11:18:24 +0800818inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
819 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500820{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500821 std::string dumpTypeLowerCopy =
822 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800823
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500824 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800825 [asyncResp, dumpType](
826 const boost::system::error_code ec,
827 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500828 if (ec)
829 {
830 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
831 messages::internalError(asyncResp->res);
832 return;
833 }
834
835 for (const std::string& path : subTreePaths)
836 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000837 sdbusplus::message::object_path objPath(path);
838 std::string logID = objPath.filename();
839 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500840 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000841 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500842 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000843 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500844 }
845 },
846 "xyz.openbmc_project.ObjectMapper",
847 "/xyz/openbmc_project/object_mapper",
848 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500849 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
850 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
851 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500852}
853
Ed Tanousb9d36b42022-02-26 21:42:46 -0800854inline static void
855 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
856 std::string& filename, std::string& timestamp,
857 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700858{
859 for (auto property : params)
860 {
861 if (property.first == "Timestamp")
862 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500863 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500864 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700865 if (value != nullptr)
866 {
867 timestamp = *value;
868 }
869 }
870 else if (property.first == "Filename")
871 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500872 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500873 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700874 if (value != nullptr)
875 {
876 filename = *value;
877 }
878 }
879 else if (property.first == "Log")
880 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500881 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500882 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700883 if (value != nullptr)
884 {
885 logfile = *value;
886 }
887 }
888 }
889}
890
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500891constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700892inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700893{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800894 /**
895 * Functions triggers appropriate requests on DBus
896 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700897 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700898 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700899 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
900 const std::shared_ptr<
901 bmcweb::AsyncResp>&
902 asyncResp) {
903 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700904 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700905 return;
906 }
907 // Collections don't include the static data added by SubRoute
908 // because it has a duplicate entry for members
909 asyncResp->res.jsonValue["@odata.type"] =
910 "#LogServiceCollection.LogServiceCollection";
911 asyncResp->res.jsonValue["@odata.id"] =
912 "/redfish/v1/Systems/system/LogServices";
913 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
914 asyncResp->res.jsonValue["Description"] =
915 "Collection of LogServices for this Computer System";
916 nlohmann::json& logServiceArray =
917 asyncResp->res.jsonValue["Members"];
918 logServiceArray = nlohmann::json::array();
919 logServiceArray.push_back(
920 {{"@odata.id",
921 "/redfish/v1/Systems/system/LogServices/EventLog"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500922#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous45ca1b82022-03-25 13:07:27 -0700923 logServiceArray.push_back(
924 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/Dump"}});
raviteja-bc9bb6862020-02-03 11:53:32 -0600925#endif
926
Jason M. Billsd53dd412019-02-12 17:16:22 -0800927#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous45ca1b82022-03-25 13:07:27 -0700928 logServiceArray.push_back(
929 {{"@odata.id",
930 "/redfish/v1/Systems/system/LogServices/Crashdump"}});
Jason M. Billsd53dd412019-02-12 17:16:22 -0800931#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800932
933#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous45ca1b82022-03-25 13:07:27 -0700934 logServiceArray.push_back(
935 {{"@odata.id",
936 "/redfish/v1/Systems/system/LogServices/HostLogger"}});
Spencer Kub7028eb2021-10-26 15:27:35 +0800937#endif
Ed Tanous45ca1b82022-03-25 13:07:27 -0700938 asyncResp->res.jsonValue["Members@odata.count"] =
939 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800940
Ed Tanous45ca1b82022-03-25 13:07:27 -0700941 crow::connections::systemBus->async_method_call(
942 [asyncResp](const boost::system::error_code ec,
943 const dbus::utility::MapperGetSubTreePathsResponse&
944 subtreePath) {
945 if (ec)
946 {
947 BMCWEB_LOG_ERROR << ec;
948 return;
949 }
950
951 for (const auto& pathStr : subtreePath)
952 {
953 if (pathStr.find("PostCode") != std::string::npos)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700954 {
Ed Tanous45ca1b82022-03-25 13:07:27 -0700955 nlohmann::json& logServiceArrayLocal =
956 asyncResp->res.jsonValue["Members"];
957 logServiceArrayLocal.push_back(
958 {{"@odata.id",
959 "/redfish/v1/Systems/system/LogServices/PostCodes"}});
960 asyncResp->res.jsonValue["Members@odata.count"] =
961 logServiceArrayLocal.size();
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700962 return;
963 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700964 }
965 },
966 "xyz.openbmc_project.ObjectMapper",
967 "/xyz/openbmc_project/object_mapper",
968 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
969 std::array<const char*, 1>{postCodeIface});
970 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700971}
972
973inline void requestRoutesEventLogService(App& app)
974{
975 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -0700976 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700977 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
978 const std::shared_ptr<
979 bmcweb::AsyncResp>&
980 asyncResp) {
981 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
982 {
983 return;
984 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700985 asyncResp->res.jsonValue["@odata.id"] =
986 "/redfish/v1/Systems/system/LogServices/EventLog";
987 asyncResp->res.jsonValue["@odata.type"] =
988 "#LogService.v1_1_0.LogService";
989 asyncResp->res.jsonValue["Name"] = "Event Log Service";
990 asyncResp->res.jsonValue["Description"] =
991 "System Event Log Service";
992 asyncResp->res.jsonValue["Id"] = "EventLog";
993 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +0530994
995 std::pair<std::string, std::string> redfishDateTimeOffset =
996 crow::utility::getDateTimeOffsetNow();
997
998 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
999 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
1000 redfishDateTimeOffset.second;
1001
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001002 asyncResp->res.jsonValue["Entries"] = {
1003 {"@odata.id",
1004 "/redfish/v1/Systems/system/LogServices/EventLog/Entries"}};
1005 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1006
George Liu0fda0f12021-11-16 10:06:17 +08001007 {"target",
1008 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001009 });
1010}
1011
1012inline void requestRoutesJournalEventLogClear(App& app)
1013{
Jason M. Bills4978b632022-02-22 14:17:43 -08001014 BMCWEB_ROUTE(
1015 app,
1016 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001017 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001018 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001019 [&app](const crow::Request& req,
1020 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1021 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1022 {
1023 return;
1024 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001025 // Clear the EventLog by deleting the log files
1026 std::vector<std::filesystem::path> redfishLogFiles;
1027 if (getRedfishLogFiles(redfishLogFiles))
ZhikuiRena3316fc2020-01-29 14:58:08 -08001028 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001029 for (const std::filesystem::path& file : redfishLogFiles)
ZhikuiRena3316fc2020-01-29 14:58:08 -08001030 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001031 std::error_code ec;
1032 std::filesystem::remove(file, ec);
ZhikuiRena3316fc2020-01-29 14:58:08 -08001033 }
1034 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001035
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001036 // Reload rsyslog so it knows to start new log files
1037 crow::connections::systemBus->async_method_call(
1038 [asyncResp](const boost::system::error_code ec) {
1039 if (ec)
1040 {
1041 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: "
1042 << ec;
1043 messages::internalError(asyncResp->res);
1044 return;
1045 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001046
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001047 messages::success(asyncResp->res);
1048 },
1049 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1050 "org.freedesktop.systemd1.Manager", "ReloadUnit",
1051 "rsyslog.service", "replace");
1052 });
1053}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001054
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001055static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001056 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001057 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001058{
Jason M. Bills95820182019-04-22 16:25:34 -07001059 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001060 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001061 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001062 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001063 {
1064 return 1;
1065 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001066 std::string timestamp = logEntry.substr(0, space);
1067 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001068 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001069 if (entryStart == std::string::npos)
1070 {
1071 return 1;
1072 }
1073 std::string_view entry(logEntry);
1074 entry.remove_prefix(entryStart);
1075 // Use split to separate the entry into its fields
1076 std::vector<std::string> logEntryFields;
1077 boost::split(logEntryFields, entry, boost::is_any_of(","),
1078 boost::token_compress_on);
1079 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001080 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001081 {
1082 return 1;
1083 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001084 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001085
Jason M. Bills4851d452019-03-28 11:27:48 -07001086 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001087 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001088
Sui Chen54417b02022-03-24 14:59:52 -07001089 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001090 {
Sui Chen54417b02022-03-24 14:59:52 -07001091 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
1092 return 0;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001093 }
1094
Sui Chen54417b02022-03-24 14:59:52 -07001095 std::string msg = message->message;
1096
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001097 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001098 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001099 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001100 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001101 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001102 // If the first string is empty, assume there are no MessageArgs
1103 std::size_t messageArgsSize = 0;
1104 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001105 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001106 messageArgsSize = logEntryFields.size() - 1;
1107 }
1108
Ed Tanous23a21a12020-07-25 04:45:05 +00001109 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001110
1111 // Fill the MessageArgs into the Message
1112 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001113 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001114 {
1115 std::string argStr = "%" + std::to_string(++i);
1116 size_t argPos = msg.find(argStr);
1117 if (argPos != std::string::npos)
1118 {
1119 msg.replace(argPos, argStr.length(), messageArg);
1120 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001121 }
1122 }
1123
Jason M. Bills95820182019-04-22 16:25:34 -07001124 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1125 // format which matches the Redfish format except for the fractional seconds
1126 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001127 std::size_t dot = timestamp.find_first_of('.');
1128 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001129 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001130 {
Jason M. Bills95820182019-04-22 16:25:34 -07001131 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001132 }
1133
1134 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001135 logEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08001136 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001137 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001138 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001139 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001140 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001141 {"Id", logEntryID},
1142 {"Message", std::move(msg)},
1143 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001144 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001145 {"EntryType", "Event"},
Sui Chen54417b02022-03-24 14:59:52 -07001146 {"Severity", message->messageSeverity},
Jason M. Bills95820182019-04-22 16:25:34 -07001147 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001148 return 0;
1149}
1150
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001151inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001152{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001153 BMCWEB_ROUTE(app,
1154 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001155 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001156 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1157 const std::shared_ptr<
1158 bmcweb::AsyncResp>&
1159 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07001160 query_param::QueryCapabilities capabilities = {
1161 .canDelegateTop = true,
1162 .canDelegateSkip = true,
1163 };
1164 query_param::Query delegatedQuery;
1165 if (!redfish::setUpRedfishRouteWithDelegation(
1166 app, req, asyncResp->res, delegatedQuery, capabilities))
Jason M. Bills4978b632022-02-22 14:17:43 -08001167 {
1168 return;
1169 }
1170 // Collections don't include the static data added by SubRoute
1171 // because it has a duplicate entry for members
1172 asyncResp->res.jsonValue["@odata.type"] =
1173 "#LogEntryCollection.LogEntryCollection";
1174 asyncResp->res.jsonValue["@odata.id"] =
1175 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1176 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1177 asyncResp->res.jsonValue["Description"] =
1178 "Collection of System Event Log Entries";
Jason M. Bills897967d2019-07-29 17:05:30 -07001179
Jason M. Bills4978b632022-02-22 14:17:43 -08001180 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1181 logEntryArray = nlohmann::json::array();
1182 // Go through the log files and create a unique ID for each
1183 // entry
1184 std::vector<std::filesystem::path> redfishLogFiles;
1185 getRedfishLogFiles(redfishLogFiles);
1186 uint64_t entryCount = 0;
1187 std::string logEntry;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001188
Jason M. Bills4978b632022-02-22 14:17:43 -08001189 // Oldest logs are in the last file, so start there and loop
1190 // backwards
1191 for (auto it = redfishLogFiles.rbegin();
1192 it < redfishLogFiles.rend(); it++)
1193 {
1194 std::ifstream logStream(*it);
1195 if (!logStream.is_open())
Andrew Geisslercb92c032018-08-17 07:56:14 -07001196 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001197 continue;
1198 }
1199
1200 // Reset the unique ID on the first entry
1201 bool firstEntry = true;
1202 while (std::getline(logStream, logEntry))
1203 {
1204 entryCount++;
1205 // Handle paging using skip (number of entries to skip
1206 // from the start) and top (number of entries to
1207 // display)
Ed Tanousc937d2b2022-04-05 09:58:00 -07001208 if (entryCount <= delegatedQuery.skip ||
1209 entryCount > delegatedQuery.skip + delegatedQuery.top)
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001210 {
1211 continue;
1212 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001213
Jason M. Bills4978b632022-02-22 14:17:43 -08001214 std::string idStr;
1215 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001216 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001217 continue;
1218 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001219
Jason M. Bills4978b632022-02-22 14:17:43 -08001220 if (firstEntry)
1221 {
1222 firstEntry = false;
1223 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001224
Jason M. Bills4978b632022-02-22 14:17:43 -08001225 logEntryArray.push_back({});
1226 nlohmann::json& bmcLogEntry = logEntryArray.back();
1227 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) !=
1228 0)
1229 {
1230 messages::internalError(asyncResp->res);
1231 return;
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001232 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001233 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001234 }
1235 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001236 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
Jason M. Bills4978b632022-02-22 14:17:43 -08001237 {
1238 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1239 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07001240 std::to_string(delegatedQuery.skip + delegatedQuery.top);
Jason M. Bills4978b632022-02-22 14:17:43 -08001241 }
1242 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001243}
Chicago Duan336e96c2019-07-15 14:22:08 +08001244
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001245inline void requestRoutesJournalEventLogEntry(App& app)
1246{
1247 BMCWEB_ROUTE(
1248 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001249 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001250 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001251 [&app](const crow::Request& req,
1252 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1253 const std::string& param) {
1254 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1255 {
1256 return;
1257 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001258 const std::string& targetID = param;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001259
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001260 // Go through the log files and check the unique ID for each
1261 // entry to find the target entry
1262 std::vector<std::filesystem::path> redfishLogFiles;
1263 getRedfishLogFiles(redfishLogFiles);
1264 std::string logEntry;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001265
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001266 // Oldest logs are in the last file, so start there and loop
1267 // backwards
1268 for (auto it = redfishLogFiles.rbegin();
1269 it < redfishLogFiles.rend(); it++)
1270 {
1271 std::ifstream logStream(*it);
1272 if (!logStream.is_open())
1273 {
1274 continue;
1275 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001276
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001277 // Reset the unique ID on the first entry
1278 bool firstEntry = true;
1279 while (std::getline(logStream, logEntry))
1280 {
1281 std::string idStr;
1282 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1283 {
1284 continue;
1285 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001286
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001287 if (firstEntry)
1288 {
1289 firstEntry = false;
1290 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001291
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001292 if (idStr == targetID)
1293 {
1294 if (fillEventLogEntryJson(
1295 idStr, logEntry,
1296 asyncResp->res.jsonValue) != 0)
1297 {
1298 messages::internalError(asyncResp->res);
1299 return;
1300 }
1301 return;
1302 }
1303 }
1304 }
1305 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07001306 messages::resourceMissingAtURI(
1307 asyncResp->res, crow::utility::urlFromPieces(targetID));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001308 });
1309}
1310
1311inline void requestRoutesDBusEventLogEntryCollection(App& app)
1312{
1313 BMCWEB_ROUTE(app,
1314 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001315 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001316 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1317 const std::shared_ptr<
1318 bmcweb::AsyncResp>&
1319 asyncResp) {
1320 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1321 {
1322 return;
1323 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001324 // Collections don't include the static data added by SubRoute
1325 // because it has a duplicate entry for members
1326 asyncResp->res.jsonValue["@odata.type"] =
1327 "#LogEntryCollection.LogEntryCollection";
1328 asyncResp->res.jsonValue["@odata.id"] =
1329 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1330 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1331 asyncResp->res.jsonValue["Description"] =
1332 "Collection of System Event Log Entries";
1333
1334 // DBus implementation of EventLog/Entries
1335 // Make call to Logging Service to find all log entry objects
Xiaochao Ma75710de2021-01-21 17:56:02 +08001336 crow::connections::systemBus->async_method_call(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001337 [asyncResp](const boost::system::error_code ec,
Ed Tanous914e2d52022-01-07 11:38:34 -08001338 const dbus::utility::ManagedObjectType& resp) {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001339 if (ec)
1340 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001341 // TODO Handle for specific error code
1342 BMCWEB_LOG_ERROR
1343 << "getLogEntriesIfaceData resp_handler got error "
1344 << ec;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001345 messages::internalError(asyncResp->res);
1346 return;
1347 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001348 nlohmann::json& entriesArray =
1349 asyncResp->res.jsonValue["Members"];
1350 entriesArray = nlohmann::json::array();
Ed Tanous9eb808c2022-01-25 10:19:23 -08001351 for (const auto& objectPath : resp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001352 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001353 const uint32_t* id = nullptr;
Ed Tanousc419c752022-01-26 12:19:54 -08001354 const uint64_t* timestamp = nullptr;
1355 const uint64_t* updateTimestamp = nullptr;
Ed Tanous914e2d52022-01-07 11:38:34 -08001356 const std::string* severity = nullptr;
1357 const std::string* message = nullptr;
1358 const std::string* filePath = nullptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001359 bool resolved = false;
Ed Tanous9eb808c2022-01-25 10:19:23 -08001360 for (const auto& interfaceMap : objectPath.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001361 {
1362 if (interfaceMap.first ==
1363 "xyz.openbmc_project.Logging.Entry")
1364 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001365 for (const auto& propertyMap :
1366 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001367 {
1368 if (propertyMap.first == "Id")
1369 {
1370 id = std::get_if<uint32_t>(
1371 &propertyMap.second);
1372 }
1373 else if (propertyMap.first == "Timestamp")
1374 {
Ed Tanousc419c752022-01-26 12:19:54 -08001375 timestamp = std::get_if<uint64_t>(
1376 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001377 }
1378 else if (propertyMap.first ==
1379 "UpdateTimestamp")
1380 {
Ed Tanousc419c752022-01-26 12:19:54 -08001381 updateTimestamp = std::get_if<uint64_t>(
1382 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001383 }
1384 else if (propertyMap.first == "Severity")
1385 {
1386 severity = std::get_if<std::string>(
1387 &propertyMap.second);
1388 }
1389 else if (propertyMap.first == "Message")
1390 {
1391 message = std::get_if<std::string>(
1392 &propertyMap.second);
1393 }
1394 else if (propertyMap.first == "Resolved")
1395 {
Ed Tanous914e2d52022-01-07 11:38:34 -08001396 const bool* resolveptr =
1397 std::get_if<bool>(
1398 &propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001399 if (resolveptr == nullptr)
1400 {
1401 messages::internalError(
1402 asyncResp->res);
1403 return;
1404 }
1405 resolved = *resolveptr;
1406 }
1407 }
1408 if (id == nullptr || message == nullptr ||
1409 severity == nullptr)
1410 {
1411 messages::internalError(asyncResp->res);
1412 return;
1413 }
1414 }
1415 else if (interfaceMap.first ==
1416 "xyz.openbmc_project.Common.FilePath")
1417 {
Ed Tanous9eb808c2022-01-25 10:19:23 -08001418 for (const auto& propertyMap :
1419 interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001420 {
1421 if (propertyMap.first == "Path")
1422 {
1423 filePath = std::get_if<std::string>(
1424 &propertyMap.second);
1425 }
1426 }
1427 }
1428 }
1429 // Object path without the
1430 // xyz.openbmc_project.Logging.Entry interface, ignore
1431 // and continue.
1432 if (id == nullptr || message == nullptr ||
Ed Tanousc419c752022-01-26 12:19:54 -08001433 severity == nullptr || timestamp == nullptr ||
1434 updateTimestamp == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001435 {
1436 continue;
1437 }
1438 entriesArray.push_back({});
1439 nlohmann::json& thisEntry = entriesArray.back();
1440 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1441 thisEntry["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08001442 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001443 std::to_string(*id);
1444 thisEntry["Name"] = "System Event Log Entry";
1445 thisEntry["Id"] = std::to_string(*id);
1446 thisEntry["Message"] = *message;
1447 thisEntry["Resolved"] = resolved;
1448 thisEntry["EntryType"] = "Event";
1449 thisEntry["Severity"] =
1450 translateSeverityDbusToRedfish(*severity);
1451 thisEntry["Created"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001452 crow::utility::getDateTimeUintMs(*timestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001453 thisEntry["Modified"] =
Ed Tanousc419c752022-01-26 12:19:54 -08001454 crow::utility::getDateTimeUintMs(*updateTimestamp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001455 if (filePath != nullptr)
1456 {
1457 thisEntry["AdditionalDataURI"] =
George Liu0fda0f12021-11-16 10:06:17 +08001458 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001459 std::to_string(*id) + "/attachment";
1460 }
1461 }
1462 std::sort(entriesArray.begin(), entriesArray.end(),
1463 [](const nlohmann::json& left,
1464 const nlohmann::json& right) {
1465 return (left["Id"] <= right["Id"]);
1466 });
1467 asyncResp->res.jsonValue["Members@odata.count"] =
1468 entriesArray.size();
Xiaochao Ma75710de2021-01-21 17:56:02 +08001469 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001470 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1471 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
1472 });
1473}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001474
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001475inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001476{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001477 BMCWEB_ROUTE(
1478 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001479 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001480 .methods(
1481 boost::beast::http::verb::
1482 get)([&app](const crow::Request& req,
1483 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1484 const std::string& param) {
1485 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001486 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001487 return;
1488 }
1489 std::string entryID = param;
1490 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001491
Ed Tanous45ca1b82022-03-25 13:07:27 -07001492 // DBus implementation of EventLog/Entries
1493 // Make call to Logging Service to find all log entry objects
1494 crow::connections::systemBus->async_method_call(
1495 [asyncResp,
1496 entryID](const boost::system::error_code ec,
1497 const dbus::utility::DBusPropertiesMap& resp) {
1498 if (ec.value() == EBADR)
1499 {
1500 messages::resourceNotFound(asyncResp->res,
1501 "EventLogEntry", entryID);
1502 return;
1503 }
1504 if (ec)
1505 {
1506 BMCWEB_LOG_ERROR
1507 << "EventLogEntry (DBus) resp_handler got error "
1508 << ec;
1509 messages::internalError(asyncResp->res);
1510 return;
1511 }
1512 const uint32_t* id = nullptr;
1513 const uint64_t* timestamp = nullptr;
1514 const uint64_t* updateTimestamp = nullptr;
1515 const std::string* severity = nullptr;
1516 const std::string* message = nullptr;
1517 const std::string* filePath = nullptr;
1518 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001519
Ed Tanous45ca1b82022-03-25 13:07:27 -07001520 for (const auto& propertyMap : resp)
1521 {
1522 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001523 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001524 id = std::get_if<uint32_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001525 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001526 else if (propertyMap.first == "Timestamp")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001527 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001528 timestamp =
1529 std::get_if<uint64_t>(&propertyMap.second);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001530 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001531 else if (propertyMap.first == "UpdateTimestamp")
1532 {
1533 updateTimestamp =
1534 std::get_if<uint64_t>(&propertyMap.second);
1535 }
1536 else if (propertyMap.first == "Severity")
1537 {
1538 severity =
1539 std::get_if<std::string>(&propertyMap.second);
1540 }
1541 else if (propertyMap.first == "Message")
1542 {
1543 message =
1544 std::get_if<std::string>(&propertyMap.second);
1545 }
1546 else if (propertyMap.first == "Resolved")
1547 {
1548 const bool* resolveptr =
1549 std::get_if<bool>(&propertyMap.second);
1550 if (resolveptr == nullptr)
1551 {
1552 messages::internalError(asyncResp->res);
1553 return;
1554 }
1555 resolved = *resolveptr;
1556 }
1557 else if (propertyMap.first == "Path")
1558 {
1559 filePath =
1560 std::get_if<std::string>(&propertyMap.second);
1561 }
1562 }
1563 if (id == nullptr || message == nullptr ||
1564 severity == nullptr || timestamp == nullptr ||
1565 updateTimestamp == nullptr)
1566 {
1567 messages::internalError(asyncResp->res);
1568 return;
1569 }
1570 asyncResp->res.jsonValue["@odata.type"] =
1571 "#LogEntry.v1_8_0.LogEntry";
1572 asyncResp->res.jsonValue["@odata.id"] =
1573 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1574 std::to_string(*id);
1575 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1576 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1577 asyncResp->res.jsonValue["Message"] = *message;
1578 asyncResp->res.jsonValue["Resolved"] = resolved;
1579 asyncResp->res.jsonValue["EntryType"] = "Event";
1580 asyncResp->res.jsonValue["Severity"] =
1581 translateSeverityDbusToRedfish(*severity);
1582 asyncResp->res.jsonValue["Created"] =
1583 crow::utility::getDateTimeUintMs(*timestamp);
1584 asyncResp->res.jsonValue["Modified"] =
1585 crow::utility::getDateTimeUintMs(*updateTimestamp);
1586 if (filePath != nullptr)
1587 {
1588 asyncResp->res.jsonValue["AdditionalDataURI"] =
1589 "/redfish/v1/Systems/system/LogServices/EventLog/attachment/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001590 std::to_string(*id);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001591 }
1592 },
1593 "xyz.openbmc_project.Logging",
1594 "/xyz/openbmc_project/logging/entry/" + entryID,
1595 "org.freedesktop.DBus.Properties", "GetAll", "");
1596 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001597
1598 BMCWEB_ROUTE(
1599 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001600 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001601 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001602 [&app](const crow::Request& req,
1603 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1604 const std::string& entryId) {
1605 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1606 {
1607 return;
1608 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001609 std::optional<bool> resolved;
1610
Willy Tu15ed6782021-12-14 11:03:16 -08001611 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1612 resolved))
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001613 {
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001614 return;
1615 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001616 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001617
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001618 crow::connections::systemBus->async_method_call(
Ed Tanous4f48d5f2021-06-21 08:27:45 -07001619 [asyncResp, entryId](const boost::system::error_code ec) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001620 if (ec)
1621 {
1622 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1623 messages::internalError(asyncResp->res);
1624 return;
1625 }
1626 },
1627 "xyz.openbmc_project.Logging",
1628 "/xyz/openbmc_project/logging/entry/" + entryId,
1629 "org.freedesktop.DBus.Properties", "Set",
1630 "xyz.openbmc_project.Logging.Entry", "Resolved",
Ed Tanous168e20c2021-12-13 14:39:53 -08001631 dbus::utility::DbusVariantType(*resolved));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001632 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001633
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001634 BMCWEB_ROUTE(
1635 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001636 .privileges(redfish::privileges::deleteLogEntry)
1637
Ed Tanous45ca1b82022-03-25 13:07:27 -07001638 .methods(boost::beast::http::verb::
1639 delete_)([&app](const crow::Request& req,
1640 const std::shared_ptr<bmcweb::AsyncResp>&
1641 asyncResp,
1642 const std::string& param) {
1643 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001644 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001645 return;
1646 }
1647 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001648
Ed Tanous45ca1b82022-03-25 13:07:27 -07001649 std::string entryID = param;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001650
Ed Tanous45ca1b82022-03-25 13:07:27 -07001651 dbus::utility::escapePathForDbus(entryID);
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001652
Ed Tanous45ca1b82022-03-25 13:07:27 -07001653 // Process response from Logging service.
1654 auto respHandler = [asyncResp,
1655 entryID](const boost::system::error_code ec) {
1656 BMCWEB_LOG_DEBUG
1657 << "EventLogEntry (DBus) doDelete callback: Done";
1658 if (ec)
1659 {
1660 if (ec.value() == EBADR)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001661 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07001662 messages::resourceNotFound(asyncResp->res, "LogEntry",
1663 entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001664 return;
1665 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001666 // TODO Handle for specific error code
1667 BMCWEB_LOG_ERROR
1668 << "EventLogEntry (DBus) doDelete respHandler got error "
1669 << ec;
1670 asyncResp->res.result(
1671 boost::beast::http::status::internal_server_error);
1672 return;
1673 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001674
Ed Tanous45ca1b82022-03-25 13:07:27 -07001675 asyncResp->res.result(boost::beast::http::status::ok);
1676 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001677
Ed Tanous45ca1b82022-03-25 13:07:27 -07001678 // Make call to Logging service to request Delete Log
1679 crow::connections::systemBus->async_method_call(
1680 respHandler, "xyz.openbmc_project.Logging",
1681 "/xyz/openbmc_project/logging/entry/" + entryID,
1682 "xyz.openbmc_project.Object.Delete", "Delete");
1683 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001684}
1685
1686inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001687{
George Liu0fda0f12021-11-16 10:06:17 +08001688 BMCWEB_ROUTE(
1689 app,
1690 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001691 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001692 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001693 [&app](const crow::Request& req,
1694 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1695 const std::string& param) {
1696 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1697 {
1698 return;
1699 }
George Liu647b3cd2021-07-05 12:43:56 +08001700 if (!http_helpers::isOctetAccepted(
1701 req.getHeaderValue("Accept")))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001702 {
1703 asyncResp->res.result(
1704 boost::beast::http::status::bad_request);
1705 return;
1706 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001707
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001708 std::string entryID = param;
1709 dbus::utility::escapePathForDbus(entryID);
1710
1711 crow::connections::systemBus->async_method_call(
1712 [asyncResp,
1713 entryID](const boost::system::error_code ec,
1714 const sdbusplus::message::unix_fd& unixfd) {
1715 if (ec.value() == EBADR)
1716 {
1717 messages::resourceNotFound(
1718 asyncResp->res, "EventLogAttachment", entryID);
1719 return;
1720 }
1721 if (ec)
1722 {
1723 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1724 messages::internalError(asyncResp->res);
1725 return;
1726 }
1727
1728 int fd = -1;
1729 fd = dup(unixfd);
1730 if (fd == -1)
1731 {
1732 messages::internalError(asyncResp->res);
1733 return;
1734 }
1735
1736 long long int size = lseek(fd, 0, SEEK_END);
1737 if (size == -1)
1738 {
1739 messages::internalError(asyncResp->res);
1740 return;
1741 }
1742
1743 // Arbitrary max size of 64kb
1744 constexpr int maxFileSize = 65536;
1745 if (size > maxFileSize)
1746 {
1747 BMCWEB_LOG_ERROR
1748 << "File size exceeds maximum allowed size of "
1749 << maxFileSize;
1750 messages::internalError(asyncResp->res);
1751 return;
1752 }
1753 std::vector<char> data(static_cast<size_t>(size));
1754 long long int rc = lseek(fd, 0, SEEK_SET);
1755 if (rc == -1)
1756 {
1757 messages::internalError(asyncResp->res);
1758 return;
1759 }
1760 rc = read(fd, data.data(), data.size());
1761 if ((rc == -1) || (rc != size))
1762 {
1763 messages::internalError(asyncResp->res);
1764 return;
1765 }
1766 close(fd);
1767
1768 std::string_view strData(data.data(), data.size());
1769 std::string output =
1770 crow::utility::base64encode(strData);
1771
1772 asyncResp->res.addHeader("Content-Type",
1773 "application/octet-stream");
1774 asyncResp->res.addHeader("Content-Transfer-Encoding",
1775 "Base64");
1776 asyncResp->res.body() = std::move(output);
1777 },
1778 "xyz.openbmc_project.Logging",
1779 "/xyz/openbmc_project/logging/entry/" + entryID,
1780 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1781 });
1782}
1783
Spencer Kub7028eb2021-10-26 15:27:35 +08001784constexpr const char* hostLoggerFolderPath = "/var/log/console";
1785
1786inline bool
1787 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1788 std::vector<std::filesystem::path>& hostLoggerFiles)
1789{
1790 std::error_code ec;
1791 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1792 if (ec)
1793 {
1794 BMCWEB_LOG_ERROR << ec.message();
1795 return false;
1796 }
1797 for (const std::filesystem::directory_entry& it : logPath)
1798 {
1799 std::string filename = it.path().filename();
1800 // Prefix of each log files is "log". Find the file and save the
1801 // path
1802 if (boost::starts_with(filename, "log"))
1803 {
1804 hostLoggerFiles.emplace_back(it.path());
1805 }
1806 }
1807 // As the log files rotate, they are appended with a ".#" that is higher for
1808 // the older logs. Since we start from oldest logs, sort the name in
1809 // descending order.
1810 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1811 AlphanumLess<std::string>());
1812
1813 return true;
1814}
1815
1816inline bool
1817 getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
Ed Tanousc937d2b2022-04-05 09:58:00 -07001818 uint64_t skip, uint64_t top,
Spencer Kub7028eb2021-10-26 15:27:35 +08001819 std::vector<std::string>& logEntries, size_t& logCount)
1820{
1821 GzFileReader logFile;
1822
1823 // Go though all log files and expose host logs.
1824 for (const std::filesystem::path& it : hostLoggerFiles)
1825 {
1826 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1827 {
1828 BMCWEB_LOG_ERROR << "fail to expose host logs";
1829 return false;
1830 }
1831 }
1832 // Get lastMessage from constructor by getter
1833 std::string lastMessage = logFile.getLastMessage();
1834 if (!lastMessage.empty())
1835 {
1836 logCount++;
1837 if (logCount > skip && logCount <= (skip + top))
1838 {
1839 logEntries.push_back(lastMessage);
1840 }
1841 }
1842 return true;
1843}
1844
1845inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1846 const std::string& msg,
1847 nlohmann::json& logEntryJson)
1848{
1849 // Fill in the log entry with the gathered data.
1850 logEntryJson = {
1851 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1852 {"@odata.id",
1853 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1854 logEntryID},
1855 {"Name", "Host Logger Entry"},
1856 {"Id", logEntryID},
1857 {"Message", msg},
1858 {"EntryType", "Oem"},
1859 {"Severity", "OK"},
1860 {"OemRecordFormat", "Host Logger Entry"}};
1861}
1862
1863inline void requestRoutesSystemHostLogger(App& app)
1864{
1865 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1866 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001867 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1868 const std::shared_ptr<
1869 bmcweb::AsyncResp>&
1870 asyncResp) {
1871 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1872 {
1873 return;
1874 }
George Liu0fda0f12021-11-16 10:06:17 +08001875 asyncResp->res.jsonValue["@odata.id"] =
1876 "/redfish/v1/Systems/system/LogServices/HostLogger";
1877 asyncResp->res.jsonValue["@odata.type"] =
1878 "#LogService.v1_1_0.LogService";
1879 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1880 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1881 asyncResp->res.jsonValue["Id"] = "HostLogger";
1882 asyncResp->res.jsonValue["Entries"] = {
1883 {"@odata.id",
1884 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries"}};
1885 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001886}
1887
1888inline void requestRoutesSystemHostLoggerCollection(App& app)
1889{
1890 BMCWEB_ROUTE(app,
1891 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1892 .privileges(redfish::privileges::getLogEntry)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001893 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
1894 const std::shared_ptr<
1895 bmcweb::AsyncResp>&
1896 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07001897 query_param::QueryCapabilities capabilities = {
1898 .canDelegateTop = true,
1899 .canDelegateSkip = true,
1900 };
1901 query_param::Query delegatedQuery;
1902 if (!redfish::setUpRedfishRouteWithDelegation(
1903 app, req, asyncResp->res, delegatedQuery, capabilities))
George Liu0fda0f12021-11-16 10:06:17 +08001904 {
1905 return;
1906 }
1907 asyncResp->res.jsonValue["@odata.id"] =
1908 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1909 asyncResp->res.jsonValue["@odata.type"] =
1910 "#LogEntryCollection.LogEntryCollection";
1911 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1912 asyncResp->res.jsonValue["Description"] =
1913 "Collection of HostLogger Entries";
1914 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1915 logEntryArray = nlohmann::json::array();
1916 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001917
George Liu0fda0f12021-11-16 10:06:17 +08001918 std::vector<std::filesystem::path> hostLoggerFiles;
1919 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1920 {
1921 BMCWEB_LOG_ERROR << "fail to get host log file path";
1922 return;
1923 }
1924
1925 size_t logCount = 0;
1926 // This vector only store the entries we want to expose that
1927 // control by skip and top.
1928 std::vector<std::string> logEntries;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001929 if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1930 delegatedQuery.top, logEntries, logCount))
George Liu0fda0f12021-11-16 10:06:17 +08001931 {
1932 messages::internalError(asyncResp->res);
1933 return;
1934 }
1935 // If vector is empty, that means skip value larger than total
1936 // log count
Ed Tanous26f69762022-01-25 09:49:11 -08001937 if (logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001938 {
1939 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1940 return;
1941 }
Ed Tanous26f69762022-01-25 09:49:11 -08001942 if (!logEntries.empty())
George Liu0fda0f12021-11-16 10:06:17 +08001943 {
1944 for (size_t i = 0; i < logEntries.size(); i++)
Spencer Kub7028eb2021-10-26 15:27:35 +08001945 {
George Liu0fda0f12021-11-16 10:06:17 +08001946 logEntryArray.push_back({});
1947 nlohmann::json& hostLogEntry = logEntryArray.back();
Ed Tanousc937d2b2022-04-05 09:58:00 -07001948 fillHostLoggerEntryJson(
1949 std::to_string(delegatedQuery.skip + i), logEntries[i],
1950 hostLogEntry);
Spencer Kub7028eb2021-10-26 15:27:35 +08001951 }
1952
George Liu0fda0f12021-11-16 10:06:17 +08001953 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07001954 if (delegatedQuery.skip + delegatedQuery.top < logCount)
Spencer Kub7028eb2021-10-26 15:27:35 +08001955 {
George Liu0fda0f12021-11-16 10:06:17 +08001956 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1957 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07001958 std::to_string(delegatedQuery.skip +
1959 delegatedQuery.top);
Spencer Kub7028eb2021-10-26 15:27:35 +08001960 }
George Liu0fda0f12021-11-16 10:06:17 +08001961 }
1962 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001963}
1964
1965inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1966{
1967 BMCWEB_ROUTE(
1968 app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1969 .privileges(redfish::privileges::getLogEntry)
1970 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001971 [&app](const crow::Request& req,
1972 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1973 const std::string& param) {
1974 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
1975 {
1976 return;
1977 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001978 const std::string& targetID = param;
1979
1980 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08001981
1982 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1983 const char* end = targetID.data() + targetID.size();
1984
1985 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
Spencer Kub7028eb2021-10-26 15:27:35 +08001986 if (ec == std::errc::invalid_argument)
1987 {
Ed Tanousace85d62021-10-26 12:45:59 -07001988 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08001989 return;
1990 }
1991 if (ec == std::errc::result_out_of_range)
1992 {
Ed Tanousace85d62021-10-26 12:45:59 -07001993 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08001994 return;
1995 }
1996
1997 std::vector<std::filesystem::path> hostLoggerFiles;
1998 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1999 {
2000 BMCWEB_LOG_ERROR << "fail to get host log file path";
2001 return;
2002 }
2003
2004 size_t logCount = 0;
2005 uint64_t top = 1;
2006 std::vector<std::string> logEntries;
2007 // We can get specific entry by skip and top. For example, if we
2008 // want to get nth entry, we can set skip = n-1 and top = 1 to
2009 // get that entry
2010 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top,
2011 logEntries, logCount))
2012 {
2013 messages::internalError(asyncResp->res);
2014 return;
2015 }
2016
2017 if (!logEntries.empty())
2018 {
2019 fillHostLoggerEntryJson(targetID, logEntries[0],
2020 asyncResp->res.jsonValue);
2021 return;
2022 }
2023
2024 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07002025 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
Spencer Kub7028eb2021-10-26 15:27:35 +08002026 });
2027}
2028
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002029inline void requestRoutesBMCLogServiceCollection(App& app)
2030{
2031 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002032 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002033 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002034 [&app](const crow::Request& req,
2035 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2036 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2037 {
2038 return;
2039 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002040 // Collections don't include the static data added by SubRoute
2041 // because it has a duplicate entry for members
2042 asyncResp->res.jsonValue["@odata.type"] =
2043 "#LogServiceCollection.LogServiceCollection";
2044 asyncResp->res.jsonValue["@odata.id"] =
2045 "/redfish/v1/Managers/bmc/LogServices";
2046 asyncResp->res.jsonValue["Name"] =
2047 "Open BMC Log Services Collection";
2048 asyncResp->res.jsonValue["Description"] =
2049 "Collection of LogServices for this Manager";
2050 nlohmann::json& logServiceArray =
2051 asyncResp->res.jsonValue["Members"];
2052 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002053#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002054 logServiceArray.push_back(
2055 {{"@odata.id",
2056 "/redfish/v1/Managers/bmc/LogServices/Dump"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002057#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002058#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002059 logServiceArray.push_back(
2060 {{"@odata.id",
2061 "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002062#endif
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002063 asyncResp->res.jsonValue["Members@odata.count"] =
2064 logServiceArray.size();
2065 });
2066}
Ed Tanous1da66f72018-07-27 16:13:37 -07002067
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002068inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002069{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002070 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002071 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002072 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002073 [&app](const crow::Request& req,
2074 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2075 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2076 {
2077 return;
2078 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002079 asyncResp->res.jsonValue["@odata.type"] =
2080 "#LogService.v1_1_0.LogService";
2081 asyncResp->res.jsonValue["@odata.id"] =
2082 "/redfish/v1/Managers/bmc/LogServices/Journal";
2083 asyncResp->res.jsonValue["Name"] =
2084 "Open BMC Journal Log Service";
2085 asyncResp->res.jsonValue["Description"] =
2086 "BMC Journal Log Service";
2087 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2088 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302089
2090 std::pair<std::string, std::string> redfishDateTimeOffset =
2091 crow::utility::getDateTimeOffsetNow();
2092 asyncResp->res.jsonValue["DateTime"] =
2093 redfishDateTimeOffset.first;
2094 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2095 redfishDateTimeOffset.second;
2096
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002097 asyncResp->res.jsonValue["Entries"] = {
2098 {"@odata.id",
2099 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"}};
2100 });
2101}
Jason M. Billse1f26342018-07-18 12:12:00 -07002102
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002103static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2104 sd_journal* journal,
2105 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002106{
2107 // Get the Log Entry contents
2108 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002109
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002110 std::string message;
2111 std::string_view syslogID;
2112 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2113 if (ret < 0)
2114 {
2115 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2116 << strerror(-ret);
2117 }
2118 if (!syslogID.empty())
2119 {
2120 message += std::string(syslogID) + ": ";
2121 }
2122
Ed Tanous39e77502019-03-04 17:35:53 -08002123 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002124 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002125 if (ret < 0)
2126 {
2127 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2128 return 1;
2129 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002130 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002131
2132 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002133 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002134 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002135 if (ret < 0)
2136 {
2137 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002138 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002139
2140 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002141 std::string entryTimeStr;
2142 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002143 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002144 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002145 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002146
2147 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002148 bmcJournalLogEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08002149 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002150 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2151 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002152 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002153 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002154 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002155 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002156 {"Severity", severity <= 2 ? "Critical"
2157 : severity <= 4 ? "Warning"
2158 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002159 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002160 {"Created", std::move(entryTimeStr)}};
2161 return 0;
2162}
2163
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002164inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002165{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002166 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002167 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002168 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2169 const std::shared_ptr<
2170 bmcweb::AsyncResp>&
2171 asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07002172 query_param::QueryCapabilities capabilities = {
2173 .canDelegateTop = true,
2174 .canDelegateSkip = true,
2175 };
2176 query_param::Query delegatedQuery;
2177 if (!redfish::setUpRedfishRouteWithDelegation(
2178 app, req, asyncResp->res, delegatedQuery, capabilities))
George Liu0fda0f12021-11-16 10:06:17 +08002179 {
2180 return;
2181 }
2182 // Collections don't include the static data added by SubRoute
2183 // because it has a duplicate entry for members
2184 asyncResp->res.jsonValue["@odata.type"] =
2185 "#LogEntryCollection.LogEntryCollection";
2186 asyncResp->res.jsonValue["@odata.id"] =
2187 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2188 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2189 asyncResp->res.jsonValue["Description"] =
2190 "Collection of BMC Journal Entries";
2191 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2192 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002193
George Liu0fda0f12021-11-16 10:06:17 +08002194 // Go through the journal and use the timestamp to create a
2195 // unique ID for each entry
2196 sd_journal* journalTmp = nullptr;
2197 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2198 if (ret < 0)
2199 {
2200 BMCWEB_LOG_ERROR << "failed to open journal: "
2201 << strerror(-ret);
2202 messages::internalError(asyncResp->res);
2203 return;
2204 }
2205 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2206 journalTmp, sd_journal_close);
2207 journalTmp = nullptr;
2208 uint64_t entryCount = 0;
2209 // Reset the unique ID on the first entry
2210 bool firstEntry = true;
2211 SD_JOURNAL_FOREACH(journal.get())
2212 {
2213 entryCount++;
2214 // Handle paging using skip (number of entries to skip from
2215 // the start) and top (number of entries to display)
Ed Tanousc937d2b2022-04-05 09:58:00 -07002216 if (entryCount <= delegatedQuery.skip ||
2217 entryCount > delegatedQuery.skip + delegatedQuery.top)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002218 {
George Liu0fda0f12021-11-16 10:06:17 +08002219 continue;
2220 }
2221
2222 std::string idStr;
2223 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2224 {
2225 continue;
2226 }
2227
2228 if (firstEntry)
2229 {
2230 firstEntry = false;
2231 }
2232
2233 logEntryArray.push_back({});
2234 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2235 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2236 bmcJournalLogEntry) != 0)
2237 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002238 messages::internalError(asyncResp->res);
2239 return;
2240 }
George Liu0fda0f12021-11-16 10:06:17 +08002241 }
2242 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
Ed Tanousc937d2b2022-04-05 09:58:00 -07002243 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
George Liu0fda0f12021-11-16 10:06:17 +08002244 {
2245 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2246 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Ed Tanousc937d2b2022-04-05 09:58:00 -07002247 std::to_string(delegatedQuery.skip + delegatedQuery.top);
George Liu0fda0f12021-11-16 10:06:17 +08002248 }
2249 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002250}
Jason M. Billse1f26342018-07-18 12:12:00 -07002251
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002252inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002253{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002254 BMCWEB_ROUTE(app,
2255 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002256 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002257 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002258 [&app](const crow::Request& req,
2259 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2260 const std::string& entryID) {
2261 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2262 {
2263 return;
2264 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002265 // Convert the unique ID back to a timestamp to find the entry
2266 uint64_t ts = 0;
2267 uint64_t index = 0;
2268 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2269 {
2270 return;
2271 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002272
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002273 sd_journal* journalTmp = nullptr;
2274 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2275 if (ret < 0)
2276 {
2277 BMCWEB_LOG_ERROR << "failed to open journal: "
2278 << strerror(-ret);
2279 messages::internalError(asyncResp->res);
2280 return;
2281 }
2282 std::unique_ptr<sd_journal, decltype(&sd_journal_close)>
2283 journal(journalTmp, sd_journal_close);
2284 journalTmp = nullptr;
2285 // Go to the timestamp in the log and move to the entry at the
2286 // index tracking the unique ID
2287 std::string idStr;
2288 bool firstEntry = true;
2289 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2290 if (ret < 0)
2291 {
2292 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2293 << strerror(-ret);
2294 messages::internalError(asyncResp->res);
2295 return;
2296 }
2297 for (uint64_t i = 0; i <= index; i++)
2298 {
2299 sd_journal_next(journal.get());
2300 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2301 {
2302 messages::internalError(asyncResp->res);
2303 return;
2304 }
2305 if (firstEntry)
2306 {
2307 firstEntry = false;
2308 }
2309 }
2310 // Confirm that the entry ID matches what was requested
2311 if (idStr != entryID)
2312 {
Ed Tanousace85d62021-10-26 12:45:59 -07002313 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002314 return;
2315 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002316
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002317 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2318 asyncResp->res.jsonValue) != 0)
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002319 {
2320 messages::internalError(asyncResp->res);
2321 return;
2322 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002323 });
2324}
2325
2326inline void requestRoutesBMCDumpService(App& app)
2327{
2328 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002329 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002330 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2331 const std::shared_ptr<
2332 bmcweb::AsyncResp>&
2333 asyncResp) {
2334 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2335 {
2336 return;
2337 }
George Liu0fda0f12021-11-16 10:06:17 +08002338 asyncResp->res.jsonValue["@odata.id"] =
2339 "/redfish/v1/Managers/bmc/LogServices/Dump";
2340 asyncResp->res.jsonValue["@odata.type"] =
2341 "#LogService.v1_2_0.LogService";
2342 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2343 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2344 asyncResp->res.jsonValue["Id"] = "Dump";
2345 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302346
George Liu0fda0f12021-11-16 10:06:17 +08002347 std::pair<std::string, std::string> redfishDateTimeOffset =
2348 crow::utility::getDateTimeOffsetNow();
2349 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2350 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2351 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302352
George Liu0fda0f12021-11-16 10:06:17 +08002353 asyncResp->res.jsonValue["Entries"] = {
2354 {"@odata.id",
2355 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"}};
2356 asyncResp->res.jsonValue["Actions"] = {
2357 {"#LogService.ClearLog",
2358 {{"target",
2359 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog"}}},
2360 {"#LogService.CollectDiagnosticData",
2361 {{"target",
2362 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData"}}}};
2363 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002364}
2365
2366inline void requestRoutesBMCDumpEntryCollection(App& app)
2367{
2368
2369 /**
2370 * Functions triggers appropriate requests on DBus
2371 */
2372 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002373 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002374 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002375 [&app](const crow::Request& req,
2376 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2377 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2378 {
2379 return;
2380 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002381 asyncResp->res.jsonValue["@odata.type"] =
2382 "#LogEntryCollection.LogEntryCollection";
2383 asyncResp->res.jsonValue["@odata.id"] =
2384 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2385 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2386 asyncResp->res.jsonValue["Description"] =
2387 "Collection of BMC Dump Entries";
2388
2389 getDumpEntryCollection(asyncResp, "BMC");
2390 });
2391}
2392
2393inline void requestRoutesBMCDumpEntry(App& app)
2394{
2395 BMCWEB_ROUTE(app,
2396 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002397 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002398 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002399 [&app](const crow::Request& req,
2400 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2401 const std::string& param) {
2402 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2403 {
2404 return;
2405 }
2406
2407 getDumpEntryById(app, req, asyncResp, param, "BMC");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002408 });
2409 BMCWEB_ROUTE(app,
2410 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002411 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002412 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002413 [&app](const crow::Request& req,
2414 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2415 const std::string& param) {
2416 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2417 {
2418 return;
2419 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002420 deleteDumpEntry(asyncResp, param, "bmc");
2421 });
2422}
2423
2424inline void requestRoutesBMCDumpCreate(App& app)
2425{
George Liu0fda0f12021-11-16 10:06:17 +08002426 BMCWEB_ROUTE(
2427 app,
2428 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002429 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002430 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002431 [&app](const crow::Request& req,
2432 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2433 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2434 {
2435 return;
2436 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002437 createDump(asyncResp, req, "BMC");
2438 });
2439}
2440
2441inline void requestRoutesBMCDumpClear(App& app)
2442{
George Liu0fda0f12021-11-16 10:06:17 +08002443 BMCWEB_ROUTE(
2444 app,
2445 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002446 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002447 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002448 [&app](const crow::Request& req,
2449 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2450 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2451 {
2452 return;
2453 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002454 clearDump(asyncResp, "BMC");
2455 });
2456}
2457
2458inline void requestRoutesSystemDumpService(App& app)
2459{
2460 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002461 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002462 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2463 const std::shared_ptr<
2464 bmcweb::AsyncResp>&
2465 asyncResp) {
2466 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002467 {
Ed Tanous45ca1b82022-03-25 13:07:27 -07002468 return;
2469 }
2470 asyncResp->res.jsonValue["@odata.id"] =
2471 "/redfish/v1/Systems/system/LogServices/Dump";
2472 asyncResp->res.jsonValue["@odata.type"] =
2473 "#LogService.v1_2_0.LogService";
2474 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2475 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2476 asyncResp->res.jsonValue["Id"] = "Dump";
2477 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302478
Ed Tanous45ca1b82022-03-25 13:07:27 -07002479 std::pair<std::string, std::string> redfishDateTimeOffset =
2480 crow::utility::getDateTimeOffsetNow();
2481 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2482 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2483 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302484
Ed Tanous45ca1b82022-03-25 13:07:27 -07002485 asyncResp->res.jsonValue["Entries"] = {
2486 {"@odata.id",
2487 "/redfish/v1/Systems/system/LogServices/Dump/Entries"}};
2488 asyncResp->res.jsonValue["Actions"] = {
2489 {"#LogService.ClearLog",
2490 {{"target",
2491 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog"}}},
2492 {"#LogService.CollectDiagnosticData",
2493 {{"target",
2494 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData"}}}};
2495 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002496}
2497
2498inline void requestRoutesSystemDumpEntryCollection(App& app)
2499{
2500
2501 /**
2502 * Functions triggers appropriate requests on DBus
2503 */
Asmitha Karunanithib2a32892021-07-13 11:56:15 -05002504 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002505 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002506 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002507 [&app](const crow::Request& req,
2508 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2509 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2510 {
2511 return;
2512 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002513 asyncResp->res.jsonValue["@odata.type"] =
2514 "#LogEntryCollection.LogEntryCollection";
2515 asyncResp->res.jsonValue["@odata.id"] =
2516 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2517 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2518 asyncResp->res.jsonValue["Description"] =
2519 "Collection of System Dump Entries";
2520
2521 getDumpEntryCollection(asyncResp, "System");
2522 });
2523}
2524
2525inline void requestRoutesSystemDumpEntry(App& app)
2526{
2527 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002528 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002529 .privileges(redfish::privileges::getLogEntry)
2530
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002531 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002532 [&app](const crow::Request& req,
2533 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2534 const std::string& param) {
2535 getDumpEntryById(app, req, asyncResp, param, "System");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002536 });
2537
2538 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002539 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002540 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002541 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002542 [&app](const crow::Request& req,
2543 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2544 const std::string& param) {
2545 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2546 {
2547 return;
2548 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002549 deleteDumpEntry(asyncResp, param, "system");
2550 });
2551}
2552
2553inline void requestRoutesSystemDumpCreate(App& app)
2554{
George Liu0fda0f12021-11-16 10:06:17 +08002555 BMCWEB_ROUTE(
2556 app,
2557 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002558 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002559 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002560 [&app](const crow::Request& req,
2561 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2562 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2563 {
2564 return;
2565 }
2566 createDump(asyncResp, req, "System");
2567 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002568}
2569
2570inline void requestRoutesSystemDumpClear(App& app)
2571{
George Liu0fda0f12021-11-16 10:06:17 +08002572 BMCWEB_ROUTE(
2573 app,
2574 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002575 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002576 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002577 [&app](const crow::Request& req,
2578 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002579
Ed Tanous45ca1b82022-03-25 13:07:27 -07002580 {
2581 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2582 {
2583 return;
2584 }
2585 clearDump(asyncResp, "System");
2586 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002587}
2588
2589inline void requestRoutesCrashdumpService(App& app)
2590{
2591 // Note: Deviated from redfish privilege registry for GET & HEAD
2592 // method for security reasons.
2593 /**
2594 * Functions triggers appropriate requests on DBus
2595 */
2596 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002597 // This is incorrect, should be:
2598 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002599 .privileges({{"ConfigureManager"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002600 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2601 const std::shared_ptr<
2602 bmcweb::AsyncResp>&
2603 asyncResp) {
2604 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2605 {
2606 return;
2607 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002608 // Copy over the static data to include the entries added by
2609 // SubRoute
2610 asyncResp->res.jsonValue["@odata.id"] =
2611 "/redfish/v1/Systems/system/LogServices/Crashdump";
2612 asyncResp->res.jsonValue["@odata.type"] =
2613 "#LogService.v1_2_0.LogService";
2614 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2615 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2616 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2617 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2618 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302619
2620 std::pair<std::string, std::string> redfishDateTimeOffset =
2621 crow::utility::getDateTimeOffsetNow();
2622 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2623 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2624 redfishDateTimeOffset.second;
2625
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002626 asyncResp->res.jsonValue["Entries"] = {
2627 {"@odata.id",
2628 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"}};
2629 asyncResp->res.jsonValue["Actions"] = {
2630 {"#LogService.ClearLog",
George Liu0fda0f12021-11-16 10:06:17 +08002631 {{"target",
2632 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog"}}},
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002633 {"#LogService.CollectDiagnosticData",
George Liu0fda0f12021-11-16 10:06:17 +08002634 {{"target",
2635 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData"}}}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002636 });
2637}
2638
2639void inline requestRoutesCrashdumpClear(App& app)
2640{
George Liu0fda0f12021-11-16 10:06:17 +08002641 BMCWEB_ROUTE(
2642 app,
2643 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002644 // This is incorrect, should be:
2645 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002646 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002647 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002648 [&app](const crow::Request& req,
2649 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2650 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2651 {
2652 return;
2653 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002654 crow::connections::systemBus->async_method_call(
2655 [asyncResp](const boost::system::error_code ec,
2656 const std::string&) {
2657 if (ec)
2658 {
2659 messages::internalError(asyncResp->res);
2660 return;
2661 }
2662 messages::success(asyncResp->res);
2663 },
2664 crashdumpObject, crashdumpPath, deleteAllInterface,
2665 "DeleteAll");
2666 });
2667}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002668
zhanghch058d1b46d2021-04-01 11:18:24 +08002669static void
2670 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2671 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002672{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002673 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002674 [asyncResp, logID,
2675 &logEntryJson](const boost::system::error_code ec,
2676 const dbus::utility::DBusPropertiesMap& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002677 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002678 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002679 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2680 if (ec.value() ==
2681 boost::system::linux_error::bad_request_descriptor)
2682 {
2683 messages::resourceNotFound(asyncResp->res, "LogEntry",
2684 logID);
2685 }
2686 else
2687 {
2688 messages::internalError(asyncResp->res);
2689 }
2690 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002691 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002692
Johnathan Mantey043a0532020-03-10 17:15:28 -07002693 std::string timestamp{};
2694 std::string filename{};
2695 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002696 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002697
2698 if (filename.empty() || timestamp.empty())
2699 {
Ed Tanousace85d62021-10-26 12:45:59 -07002700 messages::resourceMissingAtURI(
2701 asyncResp->res, crow::utility::urlFromPieces(logID));
Johnathan Mantey043a0532020-03-10 17:15:28 -07002702 return;
2703 }
2704
2705 std::string crashdumpURI =
2706 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2707 logID + "/" + filename;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002708 nlohmann::json logEntry = {
Jason M. Bills4978b632022-02-22 14:17:43 -08002709 {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
2710 {"@odata.id",
2711 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2712 logID},
2713 {"Name", "CPU Crashdump"},
2714 {"Id", logID},
2715 {"EntryType", "Oem"},
2716 {"AdditionalDataURI", std::move(crashdumpURI)},
2717 {"DiagnosticDataType", "OEM"},
2718 {"OEMDiagnosticDataType", "PECICrashdump"},
2719 {"Created", std::move(timestamp)}};
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002720
2721 // If logEntryJson references an array of LogEntry resources
2722 // ('Members' list), then push this as a new entry, otherwise set it
2723 // directly
2724 if (logEntryJson.is_array())
2725 {
2726 logEntryJson.push_back(logEntry);
2727 asyncResp->res.jsonValue["Members@odata.count"] =
2728 logEntryJson.size();
2729 }
2730 else
2731 {
2732 logEntryJson = logEntry;
2733 }
Johnathan Mantey043a0532020-03-10 17:15:28 -07002734 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002735 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002736 std::move(getStoredLogCallback), crashdumpObject,
2737 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002738 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002739}
2740
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002741inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002742{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002743 // Note: Deviated from redfish privilege registry for GET & HEAD
2744 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002745 /**
2746 * Functions triggers appropriate requests on DBus
2747 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002748 BMCWEB_ROUTE(app,
2749 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002750 // This is incorrect, should be.
2751 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002752 .privileges({{"ConfigureComponents"}})
Ed Tanous45ca1b82022-03-25 13:07:27 -07002753 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
2754 const std::shared_ptr<
2755 bmcweb::AsyncResp>&
2756 asyncResp) {
2757 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2758 {
2759 return;
2760 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002761 crow::connections::systemBus->async_method_call(
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002762 [asyncResp](const boost::system::error_code ec,
2763 const std::vector<std::string>& resp) {
2764 if (ec)
2765 {
2766 if (ec.value() !=
2767 boost::system::errc::no_such_file_or_directory)
2768 {
2769 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2770 << ec.message();
2771 messages::internalError(asyncResp->res);
2772 return;
2773 }
2774 }
2775 asyncResp->res.jsonValue["@odata.type"] =
2776 "#LogEntryCollection.LogEntryCollection";
2777 asyncResp->res.jsonValue["@odata.id"] =
2778 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2779 asyncResp->res.jsonValue["Name"] =
2780 "Open BMC Crashdump Entries";
2781 asyncResp->res.jsonValue["Description"] =
2782 "Collection of Crashdump Entries";
2783 asyncResp->res.jsonValue["Members"] =
2784 nlohmann::json::array();
Brandon Kima2dd60a2022-03-14 11:42:34 -07002785 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002786
2787 for (const std::string& path : resp)
2788 {
2789 const sdbusplus::message::object_path objPath(path);
2790 // Get the log ID
2791 std::string logID = objPath.filename();
2792 if (logID.empty())
2793 {
2794 continue;
2795 }
2796 // Add the log entry to the array
2797 logCrashdumpEntry(asyncResp, logID,
2798 asyncResp->res.jsonValue["Members"]);
2799 }
2800 },
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002801 "xyz.openbmc_project.ObjectMapper",
2802 "/xyz/openbmc_project/object_mapper",
2803 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
2804 std::array<const char*, 1>{crashdumpInterface});
2805 });
2806}
Ed Tanous1da66f72018-07-27 16:13:37 -07002807
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002808inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002809{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002810 // Note: Deviated from redfish privilege registry for GET & HEAD
2811 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002812
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002813 BMCWEB_ROUTE(
2814 app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002815 // this is incorrect, should be
2816 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07002817 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002818 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002819 [&app](const crow::Request& req,
2820 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2821 const std::string& param) {
2822 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2823 {
2824 return;
2825 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002826 const std::string& logID = param;
2827 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2828 });
2829}
Ed Tanous1da66f72018-07-27 16:13:37 -07002830
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002831inline void requestRoutesCrashdumpFile(App& app)
2832{
2833 // Note: Deviated from redfish privilege registry for GET & HEAD
2834 // method for security reasons.
2835 BMCWEB_ROUTE(
2836 app,
2837 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002838 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002839 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002840 [&app](const crow::Request& req,
2841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2842 const std::string& logID, const std::string& fileName) {
2843 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2844 {
2845 return;
2846 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002847 auto getStoredLogCallback =
Ed Tanousace85d62021-10-26 12:45:59 -07002848 [asyncResp, logID, fileName,
2849 url(boost::urls::url(req.urlView))](
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002850 const boost::system::error_code ec,
Ed Tanous168e20c2021-12-13 14:39:53 -08002851 const std::vector<std::pair<
2852 std::string, dbus::utility::DbusVariantType>>&
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002853 resp) {
2854 if (ec)
2855 {
2856 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2857 << ec.message();
2858 messages::internalError(asyncResp->res);
2859 return;
2860 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002861
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002862 std::string dbusFilename{};
2863 std::string dbusTimestamp{};
2864 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002865
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002866 parseCrashdumpParameters(resp, dbusFilename,
2867 dbusTimestamp, dbusFilepath);
2868
2869 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2870 dbusFilepath.empty())
2871 {
Ed Tanousace85d62021-10-26 12:45:59 -07002872 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002873 return;
2874 }
2875
2876 // Verify the file name parameter is correct
2877 if (fileName != dbusFilename)
2878 {
Ed Tanousace85d62021-10-26 12:45:59 -07002879 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002880 return;
2881 }
2882
2883 if (!std::filesystem::exists(dbusFilepath))
2884 {
Ed Tanousace85d62021-10-26 12:45:59 -07002885 messages::resourceMissingAtURI(asyncResp->res, url);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002886 return;
2887 }
Jason M. Bills2d314912022-01-12 13:59:01 -08002888 std::ifstream ifs(dbusFilepath,
2889 std::ios::in | std::ios::binary);
2890 asyncResp->res.body() = std::string(
2891 std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002892
2893 // Configure this to be a file download when accessed
2894 // from a browser
2895 asyncResp->res.addHeader("Content-Disposition",
2896 "attachment");
2897 };
2898 crow::connections::systemBus->async_method_call(
2899 std::move(getStoredLogCallback), crashdumpObject,
2900 crashdumpPath + std::string("/") + logID,
2901 "org.freedesktop.DBus.Properties", "GetAll",
2902 crashdumpInterface);
2903 });
2904}
2905
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002906enum class OEMDiagnosticType
2907{
2908 onDemand,
2909 telemetry,
2910 invalid,
2911};
2912
Ed Tanousf7725d72022-03-07 12:46:00 -08002913inline OEMDiagnosticType
2914 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002915{
2916 if (oemDiagStr == "OnDemand")
2917 {
2918 return OEMDiagnosticType::onDemand;
2919 }
2920 if (oemDiagStr == "Telemetry")
2921 {
2922 return OEMDiagnosticType::telemetry;
2923 }
2924
2925 return OEMDiagnosticType::invalid;
2926}
2927
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002928inline void requestRoutesCrashdumpCollect(App& app)
2929{
2930 // Note: Deviated from redfish privilege registry for GET & HEAD
2931 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08002932 BMCWEB_ROUTE(
2933 app,
2934 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002935 // The below is incorrect; Should be ConfigureManager
2936 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002937 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002938 .methods(
2939 boost::beast::http::verb::
Ed Tanous45ca1b82022-03-25 13:07:27 -07002940 post)([&app](
2941 const crow::Request& req,
2942 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2943 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
2944 {
2945 return;
2946 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002947 std::string diagnosticDataType;
2948 std::string oemDiagnosticDataType;
Willy Tu15ed6782021-12-14 11:03:16 -08002949 if (!redfish::json_util::readJsonAction(
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002950 req, asyncResp->res, "DiagnosticDataType",
2951 diagnosticDataType, "OEMDiagnosticDataType",
2952 oemDiagnosticDataType))
James Feist46229572020-02-19 15:11:58 -08002953 {
James Feist46229572020-02-19 15:11:58 -08002954 return;
2955 }
Ed Tanous1da66f72018-07-27 16:13:37 -07002956
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002957 if (diagnosticDataType != "OEM")
2958 {
2959 BMCWEB_LOG_ERROR
2960 << "Only OEM DiagnosticDataType supported for Crashdump";
2961 messages::actionParameterValueFormatError(
2962 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2963 "CollectDiagnosticData");
2964 return;
2965 }
2966
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002967 OEMDiagnosticType oemDiagType =
2968 getOEMDiagnosticType(oemDiagnosticDataType);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002969
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002970 std::string iface;
2971 std::string method;
2972 std::string taskMatchStr;
2973 if (oemDiagType == OEMDiagnosticType::onDemand)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002974 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002975 iface = crashdumpOnDemandInterface;
2976 method = "GenerateOnDemandLog";
2977 taskMatchStr = "type='signal',"
2978 "interface='org.freedesktop.DBus.Properties',"
2979 "member='PropertiesChanged',"
2980 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002981 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002982 else if (oemDiagType == OEMDiagnosticType::telemetry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002983 {
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002984 iface = crashdumpTelemetryInterface;
2985 method = "GenerateTelemetryLog";
2986 taskMatchStr = "type='signal',"
2987 "interface='org.freedesktop.DBus.Properties',"
2988 "member='PropertiesChanged',"
2989 "arg0namespace='com.intel.crashdump'";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002990 }
2991 else
2992 {
2993 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2994 << oemDiagnosticDataType;
2995 messages::actionParameterValueFormatError(
2996 asyncResp->res, oemDiagnosticDataType,
2997 "OEMDiagnosticDataType", "CollectDiagnosticData");
2998 return;
2999 }
Jason M. Billsc5a4c822022-01-06 15:51:23 -08003000
3001 auto collectCrashdumpCallback =
3002 [asyncResp, payload(task::Payload(req)),
3003 taskMatchStr](const boost::system::error_code ec,
3004 const std::string&) mutable {
3005 if (ec)
3006 {
3007 if (ec.value() ==
3008 boost::system::errc::operation_not_supported)
3009 {
3010 messages::resourceInStandby(asyncResp->res);
3011 }
3012 else if (ec.value() ==
3013 boost::system::errc::device_or_resource_busy)
3014 {
3015 messages::serviceTemporarilyUnavailable(
3016 asyncResp->res, "60");
3017 }
3018 else
3019 {
3020 messages::internalError(asyncResp->res);
3021 }
3022 return;
3023 }
3024 std::shared_ptr<task::TaskData> task =
3025 task::TaskData::createTask(
3026 [](boost::system::error_code err,
3027 sdbusplus::message::message&,
3028 const std::shared_ptr<task::TaskData>&
3029 taskData) {
3030 if (!err)
3031 {
3032 taskData->messages.emplace_back(
3033 messages::taskCompletedOK(
3034 std::to_string(taskData->index)));
3035 taskData->state = "Completed";
3036 }
3037 return task::completed;
3038 },
3039 taskMatchStr);
3040
3041 task->startTimer(std::chrono::minutes(5));
3042 task->populateResp(asyncResp->res);
3043 task->payload.emplace(std::move(payload));
3044 };
3045
3046 crow::connections::systemBus->async_method_call(
3047 std::move(collectCrashdumpCallback), crashdumpObject,
3048 crashdumpPath, iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003049 });
3050}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003051
Andrew Geisslercb92c032018-08-17 07:56:14 -07003052/**
3053 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3054 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003055inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003056{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003057 /**
3058 * Function handles POST method request.
3059 * The Clear Log actions does not require any parameter.The action deletes
3060 * all entries found in the Entries collection for this Log Service.
3061 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003062
George Liu0fda0f12021-11-16 10:06:17 +08003063 BMCWEB_ROUTE(
3064 app,
3065 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003066 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003067 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003068 [&app](const crow::Request& req,
3069 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3070 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3071 {
3072 return;
3073 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003074 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003075
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003076 // Process response from Logging service.
3077 auto respHandler = [asyncResp](
3078 const boost::system::error_code ec) {
3079 BMCWEB_LOG_DEBUG
3080 << "doClearLog resp_handler callback: Done";
3081 if (ec)
3082 {
3083 // TODO Handle for specific error code
3084 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error "
3085 << ec;
3086 asyncResp->res.result(
3087 boost::beast::http::status::internal_server_error);
3088 return;
3089 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003090
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003091 asyncResp->res.result(
3092 boost::beast::http::status::no_content);
3093 };
3094
3095 // Make call to Logging service to request Clear Log
3096 crow::connections::systemBus->async_method_call(
3097 respHandler, "xyz.openbmc_project.Logging",
3098 "/xyz/openbmc_project/logging",
3099 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3100 });
3101}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003102
3103/****************************************************
3104 * Redfish PostCode interfaces
3105 * using DBUS interface: getPostCodesTS
3106 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003107inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003108{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003109 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003110 .privileges(redfish::privileges::getLogService)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003111 .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
3112 const std::shared_ptr<
3113 bmcweb::AsyncResp>&
3114 asyncResp) {
3115 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3116 {
3117 return;
3118 }
George Liu0fda0f12021-11-16 10:06:17 +08003119 asyncResp->res.jsonValue = {
3120 {"@odata.id",
3121 "/redfish/v1/Systems/system/LogServices/PostCodes"},
3122 {"@odata.type", "#LogService.v1_1_0.LogService"},
3123 {"Name", "POST Code Log Service"},
3124 {"Description", "POST Code Log Service"},
3125 {"Id", "BIOS POST Code Log"},
3126 {"OverWritePolicy", "WrapsWhenFull"},
3127 {"Entries",
3128 {{"@odata.id",
3129 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"}}}};
Tejas Patil7c8c4052021-06-04 17:43:14 +05303130
George Liu0fda0f12021-11-16 10:06:17 +08003131 std::pair<std::string, std::string> redfishDateTimeOffset =
3132 crow::utility::getDateTimeOffsetNow();
3133 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3134 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3135 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303136
George Liu0fda0f12021-11-16 10:06:17 +08003137 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3138 {"target",
3139 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
3140 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003141}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003142
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003143inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003144{
George Liu0fda0f12021-11-16 10:06:17 +08003145 BMCWEB_ROUTE(
3146 app,
3147 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003148 // The following privilege is incorrect; It should be ConfigureManager
3149 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003150 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003151 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003152 [&app](const crow::Request& req,
3153 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3154 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3155 {
3156 return;
3157 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003158 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003159
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003160 // Make call to post-code service to request clear all
3161 crow::connections::systemBus->async_method_call(
3162 [asyncResp](const boost::system::error_code ec) {
3163 if (ec)
3164 {
3165 // TODO Handle for specific error code
3166 BMCWEB_LOG_ERROR
3167 << "doClearPostCodes resp_handler got error "
3168 << ec;
3169 asyncResp->res.result(boost::beast::http::status::
3170 internal_server_error);
3171 messages::internalError(asyncResp->res);
3172 return;
3173 }
3174 },
3175 "xyz.openbmc_project.State.Boot.PostCode0",
3176 "/xyz/openbmc_project/State/Boot/PostCode0",
3177 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3178 });
3179}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003180
3181static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003182 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303183 const boost::container::flat_map<
3184 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003185 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3186 const uint64_t skip = 0, const uint64_t top = 0)
3187{
3188 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003189 const registries::Message* message =
3190 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003191
3192 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003193 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003194
3195 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303196 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3197 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003198 {
3199 currentCodeIndex++;
3200 std::string postcodeEntryID =
3201 "B" + std::to_string(bootIndex) + "-" +
3202 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3203
3204 uint64_t usecSinceEpoch = code.first;
3205 uint64_t usTimeOffset = 0;
3206
3207 if (1 == currentCodeIndex)
3208 { // already incremented
3209 firstCodeTimeUs = code.first;
3210 }
3211 else
3212 {
3213 usTimeOffset = code.first - firstCodeTimeUs;
3214 }
3215
3216 // skip if no specific codeIndex is specified and currentCodeIndex does
3217 // not fall between top and skip
3218 if ((codeIndex == 0) &&
3219 (currentCodeIndex <= skip || currentCodeIndex > top))
3220 {
3221 continue;
3222 }
3223
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003224 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003225 // currentIndex
3226 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3227 {
3228 // This is done for simplicity. 1st entry is needed to calculate
3229 // time offset. To improve efficiency, one can get to the entry
3230 // directly (possibly with flatmap's nth method)
3231 continue;
3232 }
3233
3234 // currentCodeIndex is within top and skip or equal to specified code
3235 // index
3236
3237 // Get the Created time from the timestamp
3238 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003239 entryTimeStr =
3240 crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003241
3242 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3243 std::ostringstream hexCode;
3244 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303245 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003246 std::ostringstream timeOffsetStr;
3247 // Set Fixed -Point Notation
3248 timeOffsetStr << std::fixed;
3249 // Set precision to 4 digits
3250 timeOffsetStr << std::setprecision(4);
3251 // Add double to stream
3252 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3253 std::vector<std::string> messageArgs = {
3254 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3255
3256 // Get MessageArgs template from message registry
3257 std::string msg;
3258 if (message != nullptr)
3259 {
3260 msg = message->message;
3261
3262 // fill in this post code value
3263 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003264 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003265 {
3266 std::string argStr = "%" + std::to_string(++i);
3267 size_t argPos = msg.find(argStr);
3268 if (argPos != std::string::npos)
3269 {
3270 msg.replace(argPos, argStr.length(), messageArg);
3271 }
3272 }
3273 }
3274
Tim Leed4342a92020-04-27 11:47:58 +08003275 // Get Severity template from message registry
3276 std::string severity;
3277 if (message != nullptr)
3278 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003279 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003280 }
3281
ZhikuiRena3316fc2020-01-29 14:58:08 -08003282 // add to AsyncResp
3283 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003284 nlohmann::json& bmcLogEntry = logEntryArray.back();
George Liu0fda0f12021-11-16 10:06:17 +08003285 bmcLogEntry = {
3286 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
3287 {"@odata.id",
3288 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3289 postcodeEntryID},
3290 {"Name", "POST Code Log Entry"},
3291 {"Id", postcodeEntryID},
3292 {"Message", std::move(msg)},
3293 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3294 {"MessageArgs", std::move(messageArgs)},
3295 {"EntryType", "Event"},
3296 {"Severity", std::move(severity)},
3297 {"Created", entryTimeStr}};
George Liu647b3cd2021-07-05 12:43:56 +08003298 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3299 {
3300 bmcLogEntry["AdditionalDataURI"] =
3301 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3302 postcodeEntryID + "/attachment";
3303 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003304 }
3305}
3306
zhanghch058d1b46d2021-04-01 11:18:24 +08003307static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003308 const uint16_t bootIndex,
3309 const uint64_t codeIndex)
3310{
3311 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303312 [aResp, bootIndex,
3313 codeIndex](const boost::system::error_code ec,
3314 const boost::container::flat_map<
3315 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3316 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003317 if (ec)
3318 {
3319 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3320 messages::internalError(aResp->res);
3321 return;
3322 }
3323
3324 // skip the empty postcode boots
3325 if (postcode.empty())
3326 {
3327 return;
3328 }
3329
3330 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3331
3332 aResp->res.jsonValue["Members@odata.count"] =
3333 aResp->res.jsonValue["Members"].size();
3334 },
Jonathan Doman15124762021-01-07 17:54:17 -08003335 "xyz.openbmc_project.State.Boot.PostCode0",
3336 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003337 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3338 bootIndex);
3339}
3340
zhanghch058d1b46d2021-04-01 11:18:24 +08003341static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003342 const uint16_t bootIndex,
3343 const uint16_t bootCount,
3344 const uint64_t entryCount, const uint64_t skip,
3345 const uint64_t top)
3346{
3347 crow::connections::systemBus->async_method_call(
3348 [aResp, bootIndex, bootCount, entryCount, skip,
3349 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303350 const boost::container::flat_map<
3351 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3352 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003353 if (ec)
3354 {
3355 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3356 messages::internalError(aResp->res);
3357 return;
3358 }
3359
3360 uint64_t endCount = entryCount;
3361 if (!postcode.empty())
3362 {
3363 endCount = entryCount + postcode.size();
3364
3365 if ((skip < endCount) && ((top + skip) > entryCount))
3366 {
3367 uint64_t thisBootSkip =
3368 std::max(skip, entryCount) - entryCount;
3369 uint64_t thisBootTop =
3370 std::min(top + skip, endCount) - entryCount;
3371
3372 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3373 thisBootSkip, thisBootTop);
3374 }
3375 aResp->res.jsonValue["Members@odata.count"] = endCount;
3376 }
3377
3378 // continue to previous bootIndex
3379 if (bootIndex < bootCount)
3380 {
3381 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3382 bootCount, endCount, skip, top);
3383 }
3384 else
3385 {
3386 aResp->res.jsonValue["Members@odata.nextLink"] =
George Liu0fda0f12021-11-16 10:06:17 +08003387 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
ZhikuiRena3316fc2020-01-29 14:58:08 -08003388 std::to_string(skip + top);
3389 }
3390 },
Jonathan Doman15124762021-01-07 17:54:17 -08003391 "xyz.openbmc_project.State.Boot.PostCode0",
3392 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003393 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3394 bootIndex);
3395}
3396
zhanghch058d1b46d2021-04-01 11:18:24 +08003397static void
3398 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3399 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003400{
3401 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003402 sdbusplus::asio::getProperty<uint16_t>(
3403 *crow::connections::systemBus,
3404 "xyz.openbmc_project.State.Boot.PostCode0",
3405 "/xyz/openbmc_project/State/Boot/PostCode0",
3406 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3407 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3408 const uint16_t bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003409 if (ec)
3410 {
3411 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3412 messages::internalError(aResp->res);
3413 return;
3414 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003415 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
3416 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003417}
3418
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003419inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003420{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003421 BMCWEB_ROUTE(app,
3422 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003423 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003424 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003425 [&app](const crow::Request& req,
3426 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanousc937d2b2022-04-05 09:58:00 -07003427 query_param::QueryCapabilities capabilities = {
3428 .canDelegateTop = true,
3429 .canDelegateSkip = true,
3430 };
3431 query_param::Query delegatedQuery;
3432 if (!redfish::setUpRedfishRouteWithDelegation(
3433 app, req, asyncResp->res, delegatedQuery, capabilities))
Ed Tanous45ca1b82022-03-25 13:07:27 -07003434 {
3435 return;
3436 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003437 asyncResp->res.jsonValue["@odata.type"] =
3438 "#LogEntryCollection.LogEntryCollection";
3439 asyncResp->res.jsonValue["@odata.id"] =
3440 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3441 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3442 asyncResp->res.jsonValue["Description"] =
3443 "Collection of POST Code Log Entries";
3444 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3445 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003446
Ed Tanousc937d2b2022-04-05 09:58:00 -07003447 getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3448 delegatedQuery.top);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003449 });
3450}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003451
George Liu647b3cd2021-07-05 12:43:56 +08003452/**
3453 * @brief Parse post code ID and get the current value and index value
3454 * eg: postCodeID=B1-2, currentValue=1, index=2
3455 *
3456 * @param[in] postCodeID Post Code ID
3457 * @param[out] currentValue Current value
3458 * @param[out] index Index value
3459 *
3460 * @return bool true if the parsing is successful, false the parsing fails
3461 */
3462inline static bool parsePostCode(const std::string& postCodeID,
3463 uint64_t& currentValue, uint16_t& index)
3464{
3465 std::vector<std::string> split;
3466 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3467 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3468 {
3469 return false;
3470 }
3471
Ed Tanousca45aa32022-01-07 09:28:45 -08003472 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003473 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003474 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003475 const char* end = split[0].data() + split[0].size();
3476 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3477
3478 if (ptrIndex != end || ecIndex != std::errc())
3479 {
3480 return false;
3481 }
3482
3483 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003484
3485 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003486 end = split[1].data() + split[1].size();
3487 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003488
Ed Tanousdcf2ebc2022-01-25 10:07:45 -08003489 return ptrValue == end && ecValue != std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003490}
3491
3492inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3493{
George Liu0fda0f12021-11-16 10:06:17 +08003494 BMCWEB_ROUTE(
3495 app,
3496 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003497 .privileges(redfish::privileges::getLogEntry)
3498 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003499 [&app](const crow::Request& req,
3500 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3501 const std::string& postCodeID) {
3502 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3503 {
3504 return;
3505 }
George Liu647b3cd2021-07-05 12:43:56 +08003506 if (!http_helpers::isOctetAccepted(
3507 req.getHeaderValue("Accept")))
3508 {
3509 asyncResp->res.result(
3510 boost::beast::http::status::bad_request);
3511 return;
3512 }
3513
3514 uint64_t currentValue = 0;
3515 uint16_t index = 0;
3516 if (!parsePostCode(postCodeID, currentValue, index))
3517 {
3518 messages::resourceNotFound(asyncResp->res, "LogEntry",
3519 postCodeID);
3520 return;
3521 }
3522
3523 crow::connections::systemBus->async_method_call(
3524 [asyncResp, postCodeID, currentValue](
3525 const boost::system::error_code ec,
3526 const std::vector<std::tuple<
3527 uint64_t, std::vector<uint8_t>>>& postcodes) {
3528 if (ec.value() == EBADR)
3529 {
3530 messages::resourceNotFound(asyncResp->res,
3531 "LogEntry", postCodeID);
3532 return;
3533 }
3534 if (ec)
3535 {
3536 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3537 messages::internalError(asyncResp->res);
3538 return;
3539 }
3540
3541 size_t value = static_cast<size_t>(currentValue) - 1;
3542 if (value == std::string::npos ||
3543 postcodes.size() < currentValue)
3544 {
3545 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3546 messages::resourceNotFound(asyncResp->res,
3547 "LogEntry", postCodeID);
3548 return;
3549 }
3550
Ed Tanous9eb808c2022-01-25 10:19:23 -08003551 const auto& [tID, c] = postcodes[value];
Ed Tanous46ff87b2022-01-07 09:25:51 -08003552 if (c.empty())
George Liu647b3cd2021-07-05 12:43:56 +08003553 {
3554 BMCWEB_LOG_INFO << "No found post code data";
3555 messages::resourceNotFound(asyncResp->res,
3556 "LogEntry", postCodeID);
3557 return;
3558 }
Ed Tanous46ff87b2022-01-07 09:25:51 -08003559 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3560 const char* d = reinterpret_cast<const char*>(c.data());
3561 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003562
3563 asyncResp->res.addHeader("Content-Type",
3564 "application/octet-stream");
3565 asyncResp->res.addHeader("Content-Transfer-Encoding",
3566 "Base64");
3567 asyncResp->res.body() =
3568 crow::utility::base64encode(strData);
3569 },
3570 "xyz.openbmc_project.State.Boot.PostCode0",
3571 "/xyz/openbmc_project/State/Boot/PostCode0",
3572 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes",
3573 index);
3574 });
3575}
3576
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003577inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003578{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003579 BMCWEB_ROUTE(
3580 app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003581 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003582 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003583 [&app](const crow::Request& req,
3584 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3585 const std::string& targetID) {
3586 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
3587 {
3588 return;
3589 }
George Liu647b3cd2021-07-05 12:43:56 +08003590 uint16_t bootIndex = 0;
3591 uint64_t codeIndex = 0;
3592 if (!parsePostCode(targetID, codeIndex, bootIndex))
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003593 {
3594 // Requested ID was not found
Ed Tanousace85d62021-10-26 12:45:59 -07003595 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003596 return;
3597 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003598 if (bootIndex == 0 || codeIndex == 0)
3599 {
3600 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3601 << targetID;
3602 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003603
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003604 asyncResp->res.jsonValue["@odata.type"] =
3605 "#LogEntry.v1_4_0.LogEntry";
3606 asyncResp->res.jsonValue["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +08003607 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003608 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3609 asyncResp->res.jsonValue["Description"] =
3610 "Collection of POST Code Log Entries";
3611 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3612 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003613
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003614 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3615 });
3616}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003617
Ed Tanous1da66f72018-07-27 16:13:37 -07003618} // namespace redfish