blob: be909861e37ecc76a1376ba142d2f0faabca4d84 [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 Tanous002d39b2022-05-31 08:59:27 -070066 std::span<const MessageEntry>::iterator messageIt =
67 std::find_if(registry.begin(), registry.end(),
68 [&messageKey](const MessageEntry& messageEntry) {
69 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) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700352 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();
361 std::string dumpEntryPath =
362 "/xyz/openbmc_project/dump/" +
363 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
364
365 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
366 return AlphanumLess<std::string>()(l.first.filename(),
367 r.first.filename());
368 });
369
370 for (auto& object : resp)
371 {
372 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500373 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700374 continue;
375 }
376 uint64_t timestamp = 0;
377 uint64_t size = 0;
378 std::string dumpStatus;
379 nlohmann::json thisEntry;
380
381 std::string entryID = object.first.filename();
382 if (entryID.empty())
383 {
384 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500385 }
386
Ed Tanous002d39b2022-05-31 08:59:27 -0700387 for (auto& interfaceMap : object.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500388 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500390 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700391 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500392 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700393 if (propertyMap.first == "Status")
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500394 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 const auto* status =
396 std::get_if<std::string>(&propertyMap.second);
397 if (status == nullptr)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500398 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700399 messages::internalError(asyncResp->res);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500400 break;
401 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700402 dumpStatus = *status;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500403 }
404 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700405 }
406 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
407 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500408
Ed Tanous002d39b2022-05-31 08:59:27 -0700409 for (auto& propertyMap : interfaceMap.second)
410 {
411 if (propertyMap.first == "Size")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500412 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700413 const auto* sizePtr =
414 std::get_if<uint64_t>(&propertyMap.second);
415 if (sizePtr == nullptr)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500416 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700417 messages::internalError(asyncResp->res);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500418 break;
419 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 size = *sizePtr;
421 break;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500422 }
423 }
424 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700425 else if (interfaceMap.first ==
426 "xyz.openbmc_project.Time.EpochTime")
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500427 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500428
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 for (const auto& propertyMap : interfaceMap.second)
430 {
431 if (propertyMap.first == "Elapsed")
432 {
433 const uint64_t* usecsTimeStamp =
434 std::get_if<uint64_t>(&propertyMap.second);
435 if (usecsTimeStamp == nullptr)
436 {
437 messages::internalError(asyncResp->res);
438 break;
439 }
440 timestamp = (*usecsTimeStamp / 1000 / 1000);
441 break;
442 }
443 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500444 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500445 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700446
447 if (dumpStatus !=
448 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
449 !dumpStatus.empty())
450 {
451 // Dump status is not Complete, no need to enumerate
452 continue;
453 }
454
455 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
456 thisEntry["@odata.id"] = dumpPath + entryID;
457 thisEntry["Id"] = entryID;
458 thisEntry["EntryType"] = "Event";
459 thisEntry["Created"] = crow::utility::getDateTimeUint(timestamp);
460 thisEntry["Name"] = dumpType + " Dump Entry";
461
462 thisEntry["AdditionalDataSizeBytes"] = size;
463
464 if (dumpType == "BMC")
465 {
466 thisEntry["DiagnosticDataType"] = "Manager";
467 thisEntry["AdditionalDataURI"] =
468 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
469 entryID + "/attachment";
470 }
471 else if (dumpType == "System")
472 {
473 thisEntry["DiagnosticDataType"] = "OEM";
474 thisEntry["OEMDiagnosticDataType"] = "System";
475 thisEntry["AdditionalDataURI"] =
476 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
477 entryID + "/attachment";
478 }
479 entriesArray.push_back(std::move(thisEntry));
480 }
481 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500482 },
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
Claire Weinanc7a6d662022-06-13 16:36:39 -0700488 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800489 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500490{
491 std::string dumpPath;
492 if (dumpType == "BMC")
493 {
494 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
495 }
496 else if (dumpType == "System")
497 {
498 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
499 }
500 else
501 {
502 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
503 messages::internalError(asyncResp->res);
504 return;
505 }
506
507 crow::connections::systemBus->async_method_call(
Ed Tanous711ac7a2021-12-20 09:34:41 -0800508 [asyncResp, entryID, dumpPath,
509 dumpType](const boost::system::error_code ec,
510 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 if (ec)
512 {
513 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
514 messages::internalError(asyncResp->res);
515 return;
516 }
517
518 bool foundDumpEntry = false;
519 std::string dumpEntryPath =
520 "/xyz/openbmc_project/dump/" +
521 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
522
523 for (const auto& objectPath : resp)
524 {
525 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500526 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700527 continue;
528 }
529
530 foundDumpEntry = true;
531 uint64_t timestamp = 0;
532 uint64_t size = 0;
533 std::string dumpStatus;
534
535 for (const auto& interfaceMap : objectPath.second)
536 {
537 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
538 {
539 for (const auto& propertyMap : interfaceMap.second)
540 {
541 if (propertyMap.first == "Status")
542 {
543 const std::string* status =
544 std::get_if<std::string>(&propertyMap.second);
545 if (status == nullptr)
546 {
547 messages::internalError(asyncResp->res);
548 break;
549 }
550 dumpStatus = *status;
551 }
552 }
553 }
554 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
555 {
556 for (const auto& propertyMap : interfaceMap.second)
557 {
558 if (propertyMap.first == "Size")
559 {
560 const uint64_t* sizePtr =
561 std::get_if<uint64_t>(&propertyMap.second);
562 if (sizePtr == nullptr)
563 {
564 messages::internalError(asyncResp->res);
565 break;
566 }
567 size = *sizePtr;
568 break;
569 }
570 }
571 }
572 else if (interfaceMap.first ==
573 "xyz.openbmc_project.Time.EpochTime")
574 {
575 for (const auto& propertyMap : interfaceMap.second)
576 {
577 if (propertyMap.first == "Elapsed")
578 {
579 const uint64_t* usecsTimeStamp =
580 std::get_if<uint64_t>(&propertyMap.second);
581 if (usecsTimeStamp == nullptr)
582 {
583 messages::internalError(asyncResp->res);
584 break;
585 }
586 timestamp = *usecsTimeStamp / 1000 / 1000;
587 break;
588 }
589 }
590 }
591 }
592
593 if (dumpStatus !=
594 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
595 !dumpStatus.empty())
596 {
597 // Dump status is not Complete
598 // return not found until status is changed to Completed
599 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
600 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500601 return;
602 }
603
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 asyncResp->res.jsonValue["@odata.type"] =
605 "#LogEntry.v1_8_0.LogEntry";
606 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
607 asyncResp->res.jsonValue["Id"] = entryID;
608 asyncResp->res.jsonValue["EntryType"] = "Event";
609 asyncResp->res.jsonValue["Created"] =
610 crow::utility::getDateTimeUint(timestamp);
611 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500612
Ed Tanous002d39b2022-05-31 08:59:27 -0700613 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
614
615 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500616 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700617 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
618 asyncResp->res.jsonValue["AdditionalDataURI"] =
619 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
620 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500621 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700622 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500623 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
625 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
626 asyncResp->res.jsonValue["AdditionalDataURI"] =
627 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
628 entryID + "/attachment";
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500629 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700630 }
631 if (!foundDumpEntry)
632 {
633 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
634 messages::internalError(asyncResp->res);
635 return;
636 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500637 },
638 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
639 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
640}
641
zhanghch058d1b46d2021-04-01 11:18:24 +0800642inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800643 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500644 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500645{
Ed Tanous002d39b2022-05-31 08:59:27 -0700646 auto respHandler =
647 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500648 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
649 if (ec)
650 {
George Liu3de8d8b2021-03-22 17:49:39 +0800651 if (ec.value() == EBADR)
652 {
653 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
654 return;
655 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
657 << ec;
658 messages::internalError(asyncResp->res);
659 return;
660 }
661 };
662 crow::connections::systemBus->async_method_call(
663 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500664 "/xyz/openbmc_project/dump/" +
665 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
666 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500667 "xyz.openbmc_project.Object.Delete", "Delete");
668}
669
zhanghch058d1b46d2021-04-01 11:18:24 +0800670inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700671 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800672 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
673 const uint32_t& dumpId, const std::string& dumpPath,
674 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500675{
676 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500677 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500678 boost::system::error_code err, sdbusplus::message::message& m,
679 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700680 if (err)
681 {
682 BMCWEB_LOG_ERROR << "Error in creating a dump";
683 taskData->state = "Cancelled";
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500684 return task::completed;
Ed Tanous002d39b2022-05-31 08:59:27 -0700685 }
686
687 dbus::utility::DBusInteracesMap interfacesList;
688
689 sdbusplus::message::object_path objPath;
690
691 m.read(objPath, interfacesList);
692
693 if (objPath.str ==
694 "/xyz/openbmc_project/dump/" +
695 std::string(boost::algorithm::to_lower_copy(dumpType)) +
696 "/entry/" + std::to_string(dumpId))
697 {
698 nlohmann::json retMessage = messages::success();
699 taskData->messages.emplace_back(retMessage);
700
701 std::string headerLoc =
702 "Location: " + dumpPath + std::to_string(dumpId);
703 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
704
705 taskData->state = "Completed";
706 return task::completed;
707 }
708 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500709 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800710 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500711 "member='InterfacesAdded', "
712 "path='/xyz/openbmc_project/dump'");
713
714 task->startTimer(std::chrono::minutes(3));
715 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700716 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500717}
718
zhanghch058d1b46d2021-04-01 11:18:24 +0800719inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
720 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500721{
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500722 std::string dumpPath;
723 if (dumpType == "BMC")
724 {
725 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
726 }
727 else if (dumpType == "System")
728 {
729 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
730 }
731 else
732 {
733 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
734 messages::internalError(asyncResp->res);
735 return;
736 }
737
738 std::optional<std::string> diagnosticDataType;
739 std::optional<std::string> oemDiagnosticDataType;
740
Willy Tu15ed6782021-12-14 11:03:16 -0800741 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500742 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
743 "OEMDiagnosticDataType", oemDiagnosticDataType))
744 {
745 return;
746 }
747
748 if (dumpType == "System")
749 {
750 if (!oemDiagnosticDataType || !diagnosticDataType)
751 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800752 BMCWEB_LOG_ERROR
753 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500754 messages::actionParameterMissing(
755 asyncResp->res, "CollectDiagnosticData",
756 "DiagnosticDataType & OEMDiagnosticDataType");
757 return;
758 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700759 if ((*oemDiagnosticDataType != "System") ||
760 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500761 {
762 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700763 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500764 return;
765 }
766 }
767 else if (dumpType == "BMC")
768 {
769 if (!diagnosticDataType)
770 {
George Liu0fda0f12021-11-16 10:06:17 +0800771 BMCWEB_LOG_ERROR
772 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500773 messages::actionParameterMissing(
774 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
775 return;
776 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700777 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500778 {
779 BMCWEB_LOG_ERROR
780 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700781 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500782 return;
783 }
784 }
785
786 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700787 [asyncResp, payload(task::Payload(req)), dumpPath,
788 dumpType](const boost::system::error_code ec,
789 const uint32_t& dumpId) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700790 if (ec)
791 {
792 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
793 messages::internalError(asyncResp->res);
794 return;
795 }
796 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500797
Ed Tanous002d39b2022-05-31 08:59:27 -0700798 createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
799 dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500800 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500801 "xyz.openbmc_project.Dump.Manager",
802 "/xyz/openbmc_project/dump/" +
803 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500804 "xyz.openbmc_project.Dump.Create", "CreateDump");
805}
806
zhanghch058d1b46d2021-04-01 11:18:24 +0800807inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
808 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500809{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500810 std::string dumpTypeLowerCopy =
811 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800812
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500813 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800814 [asyncResp, dumpType](
815 const boost::system::error_code ec,
816 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700817 if (ec)
818 {
819 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
820 messages::internalError(asyncResp->res);
821 return;
822 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500823
Ed Tanous002d39b2022-05-31 08:59:27 -0700824 for (const std::string& path : subTreePaths)
825 {
826 sdbusplus::message::object_path objPath(path);
827 std::string logID = objPath.filename();
828 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500829 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700830 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500831 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700832 deleteDumpEntry(asyncResp, logID, dumpType);
833 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500834 },
835 "xyz.openbmc_project.ObjectMapper",
836 "/xyz/openbmc_project/object_mapper",
837 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500838 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
839 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
840 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500841}
842
Ed Tanousb9d36b42022-02-26 21:42:46 -0800843inline static void
844 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
845 std::string& filename, std::string& timestamp,
846 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700847{
848 for (auto property : params)
849 {
850 if (property.first == "Timestamp")
851 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500852 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500853 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700854 if (value != nullptr)
855 {
856 timestamp = *value;
857 }
858 }
859 else if (property.first == "Filename")
860 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500861 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500862 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700863 if (value != nullptr)
864 {
865 filename = *value;
866 }
867 }
868 else if (property.first == "Log")
869 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500870 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500871 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700872 if (value != nullptr)
873 {
874 logfile = *value;
875 }
876 }
877 }
878}
879
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500880constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700881inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700882{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800883 /**
884 * Functions triggers appropriate requests on DBus
885 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700886 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700887 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700888 .methods(boost::beast::http::verb::get)(
889 [&app](const crow::Request& req,
890 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000891 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700892 {
893 return;
894 }
895 // Collections don't include the static data added by SubRoute
896 // because it has a duplicate entry for members
897 asyncResp->res.jsonValue["@odata.type"] =
898 "#LogServiceCollection.LogServiceCollection";
899 asyncResp->res.jsonValue["@odata.id"] =
900 "/redfish/v1/Systems/system/LogServices";
901 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
902 asyncResp->res.jsonValue["Description"] =
903 "Collection of LogServices for this Computer System";
904 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
905 logServiceArray = nlohmann::json::array();
906 nlohmann::json::object_t eventLog;
907 eventLog["@odata.id"] =
908 "/redfish/v1/Systems/system/LogServices/EventLog";
909 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500910#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700911 nlohmann::json::object_t dumpLog;
912 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
913 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -0600914#endif
915
Jason M. Billsd53dd412019-02-12 17:16:22 -0800916#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700917 nlohmann::json::object_t crashdump;
918 crashdump["@odata.id"] =
919 "/redfish/v1/Systems/system/LogServices/Crashdump";
920 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -0800921#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800922
923#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -0700924 nlohmann::json::object_t hostlogger;
925 hostlogger["@odata.id"] =
926 "/redfish/v1/Systems/system/LogServices/HostLogger";
927 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +0800928#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700929 asyncResp->res.jsonValue["Members@odata.count"] =
930 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800931
Ed Tanous002d39b2022-05-31 08:59:27 -0700932 crow::connections::systemBus->async_method_call(
933 [asyncResp](const boost::system::error_code ec,
934 const dbus::utility::MapperGetSubTreePathsResponse&
935 subtreePath) {
936 if (ec)
937 {
938 BMCWEB_LOG_ERROR << ec;
939 return;
940 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700941
Ed Tanous002d39b2022-05-31 08:59:27 -0700942 for (const auto& pathStr : subtreePath)
943 {
944 if (pathStr.find("PostCode") != std::string::npos)
945 {
946 nlohmann::json& logServiceArrayLocal =
947 asyncResp->res.jsonValue["Members"];
948 logServiceArrayLocal.push_back(
949 {{"@odata.id",
950 "/redfish/v1/Systems/system/LogServices/PostCodes"}});
951 asyncResp->res.jsonValue["Members@odata.count"] =
952 logServiceArrayLocal.size();
953 return;
954 }
955 }
956 },
957 "xyz.openbmc_project.ObjectMapper",
958 "/xyz/openbmc_project/object_mapper",
959 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
960 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -0700961 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700962}
963
964inline void requestRoutesEventLogService(App& app)
965{
966 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -0700967 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700968 .methods(boost::beast::http::verb::get)(
969 [&app](const crow::Request& req,
970 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000971 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700972 {
973 return;
974 }
975 asyncResp->res.jsonValue["@odata.id"] =
976 "/redfish/v1/Systems/system/LogServices/EventLog";
977 asyncResp->res.jsonValue["@odata.type"] =
978 "#LogService.v1_1_0.LogService";
979 asyncResp->res.jsonValue["Name"] = "Event Log Service";
980 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
981 asyncResp->res.jsonValue["Id"] = "EventLog";
982 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +0530983
Ed Tanous002d39b2022-05-31 08:59:27 -0700984 std::pair<std::string, std::string> redfishDateTimeOffset =
985 crow::utility::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +0530986
Ed Tanous002d39b2022-05-31 08:59:27 -0700987 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
988 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
989 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +0530990
Ed Tanous002d39b2022-05-31 08:59:27 -0700991 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
992 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
993 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700994
Ed Tanous002d39b2022-05-31 08:59:27 -0700995 {"target",
996 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700997 });
998}
999
1000inline void requestRoutesJournalEventLogClear(App& app)
1001{
Jason M. Bills4978b632022-02-22 14:17:43 -08001002 BMCWEB_ROUTE(
1003 app,
1004 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001005 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001006 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001007 [&app](const crow::Request& req,
1008 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001009 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001010 {
1011 return;
1012 }
1013 // Clear the EventLog by deleting the log files
1014 std::vector<std::filesystem::path> redfishLogFiles;
1015 if (getRedfishLogFiles(redfishLogFiles))
1016 {
1017 for (const std::filesystem::path& file : redfishLogFiles)
1018 {
1019 std::error_code ec;
1020 std::filesystem::remove(file, ec);
1021 }
1022 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001023
Ed Tanous002d39b2022-05-31 08:59:27 -07001024 // Reload rsyslog so it knows to start new log files
1025 crow::connections::systemBus->async_method_call(
1026 [asyncResp](const boost::system::error_code ec) {
1027 if (ec)
1028 {
1029 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1030 messages::internalError(asyncResp->res);
1031 return;
1032 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001033
Ed Tanous002d39b2022-05-31 08:59:27 -07001034 messages::success(asyncResp->res);
1035 },
1036 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1037 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1038 "replace");
1039 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001040}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001041
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001042static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001043 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001044 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001045{
Jason M. Bills95820182019-04-22 16:25:34 -07001046 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001047 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001048 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001049 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001050 {
1051 return 1;
1052 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001053 std::string timestamp = logEntry.substr(0, space);
1054 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001055 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001056 if (entryStart == std::string::npos)
1057 {
1058 return 1;
1059 }
1060 std::string_view entry(logEntry);
1061 entry.remove_prefix(entryStart);
1062 // Use split to separate the entry into its fields
1063 std::vector<std::string> logEntryFields;
1064 boost::split(logEntryFields, entry, boost::is_any_of(","),
1065 boost::token_compress_on);
1066 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001067 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001068 {
1069 return 1;
1070 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001071 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001072
Jason M. Bills4851d452019-03-28 11:27:48 -07001073 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001074 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001075
Sui Chen54417b02022-03-24 14:59:52 -07001076 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001077 {
Sui Chen54417b02022-03-24 14:59:52 -07001078 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
1079 return 0;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001080 }
1081
Sui Chen54417b02022-03-24 14:59:52 -07001082 std::string msg = message->message;
1083
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001084 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001085 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001086 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001087 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001088 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001089 // If the first string is empty, assume there are no MessageArgs
1090 std::size_t messageArgsSize = 0;
1091 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001092 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001093 messageArgsSize = logEntryFields.size() - 1;
1094 }
1095
Ed Tanous23a21a12020-07-25 04:45:05 +00001096 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001097
1098 // Fill the MessageArgs into the Message
1099 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001100 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001101 {
1102 std::string argStr = "%" + std::to_string(++i);
1103 size_t argPos = msg.find(argStr);
1104 if (argPos != std::string::npos)
1105 {
1106 msg.replace(argPos, argStr.length(), messageArg);
1107 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001108 }
1109 }
1110
Jason M. Bills95820182019-04-22 16:25:34 -07001111 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1112 // format which matches the Redfish format except for the fractional seconds
1113 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001114 std::size_t dot = timestamp.find_first_of('.');
1115 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001116 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001117 {
Jason M. Bills95820182019-04-22 16:25:34 -07001118 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001119 }
1120
1121 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001122 logEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08001123 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001124 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001125 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001126 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001127 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001128 {"Id", logEntryID},
1129 {"Message", std::move(msg)},
1130 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001131 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001132 {"EntryType", "Event"},
Sui Chen54417b02022-03-24 14:59:52 -07001133 {"Severity", message->messageSeverity},
Jason M. Bills95820182019-04-22 16:25:34 -07001134 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001135 return 0;
1136}
1137
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001138inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001139{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001140 BMCWEB_ROUTE(app,
1141 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001142 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001143 .methods(boost::beast::http::verb::get)(
1144 [&app](const crow::Request& req,
1145 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1146 query_param::QueryCapabilities capabilities = {
1147 .canDelegateTop = true,
1148 .canDelegateSkip = true,
1149 };
1150 query_param::Query delegatedQuery;
1151 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001152 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001153 {
1154 return;
1155 }
1156 // Collections don't include the static data added by SubRoute
1157 // because it has a duplicate entry for members
1158 asyncResp->res.jsonValue["@odata.type"] =
1159 "#LogEntryCollection.LogEntryCollection";
1160 asyncResp->res.jsonValue["@odata.id"] =
1161 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1162 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1163 asyncResp->res.jsonValue["Description"] =
1164 "Collection of System Event Log Entries";
1165
1166 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1167 logEntryArray = nlohmann::json::array();
1168 // Go through the log files and create a unique ID for each
1169 // entry
1170 std::vector<std::filesystem::path> redfishLogFiles;
1171 getRedfishLogFiles(redfishLogFiles);
1172 uint64_t entryCount = 0;
1173 std::string logEntry;
1174
1175 // Oldest logs are in the last file, so start there and loop
1176 // backwards
1177 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1178 it++)
1179 {
1180 std::ifstream logStream(*it);
1181 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001182 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001183 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001184 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001185
Ed Tanous002d39b2022-05-31 08:59:27 -07001186 // Reset the unique ID on the first entry
1187 bool firstEntry = true;
1188 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001189 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001190 entryCount++;
1191 // Handle paging using skip (number of entries to skip
1192 // from the start) and top (number of entries to
1193 // display)
1194 if (entryCount <= delegatedQuery.skip ||
1195 entryCount > delegatedQuery.skip + delegatedQuery.top)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001196 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001197 continue;
1198 }
1199
Ed Tanous002d39b2022-05-31 08:59:27 -07001200 std::string idStr;
1201 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001202 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001203 continue;
1204 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001205
Ed Tanous002d39b2022-05-31 08:59:27 -07001206 if (firstEntry)
1207 {
1208 firstEntry = false;
1209 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001210
Ed Tanous002d39b2022-05-31 08:59:27 -07001211 logEntryArray.push_back({});
1212 nlohmann::json& bmcLogEntry = logEntryArray.back();
1213 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1214 {
1215 messages::internalError(asyncResp->res);
1216 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001217 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001218 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001219 }
1220 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1221 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
1222 {
1223 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1224 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
1225 std::to_string(delegatedQuery.skip + delegatedQuery.top);
1226 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001227 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001228}
Chicago Duan336e96c2019-07-15 14:22:08 +08001229
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001230inline void requestRoutesJournalEventLogEntry(App& app)
1231{
1232 BMCWEB_ROUTE(
1233 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001234 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001235 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001236 [&app](const crow::Request& req,
1237 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1238 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001239 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001240 {
1241 return;
1242 }
1243 const std::string& targetID = param;
1244
1245 // Go through the log files and check the unique ID for each
1246 // entry to find the target entry
1247 std::vector<std::filesystem::path> redfishLogFiles;
1248 getRedfishLogFiles(redfishLogFiles);
1249 std::string logEntry;
1250
1251 // Oldest logs are in the last file, so start there and loop
1252 // backwards
1253 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1254 it++)
1255 {
1256 std::ifstream logStream(*it);
1257 if (!logStream.is_open())
1258 {
1259 continue;
1260 }
1261
1262 // Reset the unique ID on the first entry
1263 bool firstEntry = true;
1264 while (std::getline(logStream, logEntry))
1265 {
1266 std::string idStr;
1267 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001268 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001269 continue;
1270 }
1271
1272 if (firstEntry)
1273 {
1274 firstEntry = false;
1275 }
1276
1277 if (idStr == targetID)
1278 {
1279 if (fillEventLogEntryJson(idStr, logEntry,
1280 asyncResp->res.jsonValue) != 0)
1281 {
1282 messages::internalError(asyncResp->res);
1283 return;
1284 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001285 return;
1286 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001287 }
1288 }
1289 // Requested ID was not found
1290 messages::resourceMissingAtURI(asyncResp->res,
1291 crow::utility::urlFromPieces(targetID));
1292 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001293}
1294
1295inline void requestRoutesDBusEventLogEntryCollection(App& app)
1296{
1297 BMCWEB_ROUTE(app,
1298 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001299 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001300 .methods(boost::beast::http::verb::get)(
1301 [&app](const crow::Request& req,
1302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001303 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001304 {
1305 return;
1306 }
1307 // Collections don't include the static data added by SubRoute
1308 // because it has a duplicate entry for members
1309 asyncResp->res.jsonValue["@odata.type"] =
1310 "#LogEntryCollection.LogEntryCollection";
1311 asyncResp->res.jsonValue["@odata.id"] =
1312 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1313 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1314 asyncResp->res.jsonValue["Description"] =
1315 "Collection of System Event Log Entries";
1316
1317 // DBus implementation of EventLog/Entries
1318 // Make call to Logging Service to find all log entry objects
1319 crow::connections::systemBus->async_method_call(
1320 [asyncResp](const boost::system::error_code ec,
1321 const dbus::utility::ManagedObjectType& resp) {
1322 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001323 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001324 // TODO Handle for specific error code
1325 BMCWEB_LOG_ERROR
1326 << "getLogEntriesIfaceData resp_handler got error " << ec;
1327 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001328 return;
1329 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001330 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1331 entriesArray = nlohmann::json::array();
1332 for (const auto& objectPath : resp)
1333 {
1334 const uint32_t* id = nullptr;
1335 const uint64_t* timestamp = nullptr;
1336 const uint64_t* updateTimestamp = nullptr;
1337 const std::string* severity = nullptr;
1338 const std::string* message = nullptr;
1339 const std::string* filePath = nullptr;
1340 bool resolved = false;
1341 for (const auto& interfaceMap : objectPath.second)
1342 {
1343 if (interfaceMap.first ==
1344 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001345 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001346 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001347 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001348 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001349 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001350 id = std::get_if<uint32_t>(&propertyMap.second);
1351 }
1352 else if (propertyMap.first == "Timestamp")
1353 {
1354 timestamp =
1355 std::get_if<uint64_t>(&propertyMap.second);
1356 }
1357 else if (propertyMap.first == "UpdateTimestamp")
1358 {
1359 updateTimestamp =
1360 std::get_if<uint64_t>(&propertyMap.second);
1361 }
1362 else if (propertyMap.first == "Severity")
1363 {
1364 severity = std::get_if<std::string>(
1365 &propertyMap.second);
1366 }
1367 else if (propertyMap.first == "Message")
1368 {
1369 message = std::get_if<std::string>(
1370 &propertyMap.second);
1371 }
1372 else if (propertyMap.first == "Resolved")
1373 {
1374 const bool* resolveptr =
1375 std::get_if<bool>(&propertyMap.second);
1376 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001377 {
1378 messages::internalError(asyncResp->res);
1379 return;
1380 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001381 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001382 }
1383 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001384 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001385 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001386 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001387 messages::internalError(asyncResp->res);
1388 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001389 }
1390 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001391 else if (interfaceMap.first ==
1392 "xyz.openbmc_project.Common.FilePath")
1393 {
1394 for (const auto& propertyMap : interfaceMap.second)
1395 {
1396 if (propertyMap.first == "Path")
1397 {
1398 filePath = std::get_if<std::string>(
1399 &propertyMap.second);
1400 }
1401 }
1402 }
1403 }
1404 // Object path without the
1405 // xyz.openbmc_project.Logging.Entry interface, ignore
1406 // and continue.
1407 if (id == nullptr || message == nullptr ||
1408 severity == nullptr || timestamp == nullptr ||
1409 updateTimestamp == nullptr)
1410 {
1411 continue;
1412 }
1413 entriesArray.push_back({});
1414 nlohmann::json& thisEntry = entriesArray.back();
1415 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1416 thisEntry["@odata.id"] =
1417 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1418 std::to_string(*id);
1419 thisEntry["Name"] = "System Event Log Entry";
1420 thisEntry["Id"] = std::to_string(*id);
1421 thisEntry["Message"] = *message;
1422 thisEntry["Resolved"] = resolved;
1423 thisEntry["EntryType"] = "Event";
1424 thisEntry["Severity"] =
1425 translateSeverityDbusToRedfish(*severity);
1426 thisEntry["Created"] =
1427 crow::utility::getDateTimeUintMs(*timestamp);
1428 thisEntry["Modified"] =
1429 crow::utility::getDateTimeUintMs(*updateTimestamp);
1430 if (filePath != nullptr)
1431 {
1432 thisEntry["AdditionalDataURI"] =
1433 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1434 std::to_string(*id) + "/attachment";
1435 }
1436 }
1437 std::sort(
1438 entriesArray.begin(), entriesArray.end(),
1439 [](const nlohmann::json& left, const nlohmann::json& right) {
1440 return (left["Id"] <= right["Id"]);
1441 });
1442 asyncResp->res.jsonValue["Members@odata.count"] =
1443 entriesArray.size();
1444 },
1445 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1446 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001447 });
1448}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001449
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001450inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001451{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001452 BMCWEB_ROUTE(
1453 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001454 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001455 .methods(boost::beast::http::verb::get)(
1456 [&app](const crow::Request& req,
1457 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1458 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001459 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001460 {
1461 return;
1462 }
1463 std::string entryID = param;
1464 dbus::utility::escapePathForDbus(entryID);
1465
1466 // DBus implementation of EventLog/Entries
1467 // Make call to Logging Service to find all log entry objects
1468 crow::connections::systemBus->async_method_call(
1469 [asyncResp, entryID](const boost::system::error_code ec,
1470 const dbus::utility::DBusPropertiesMap& resp) {
1471 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001472 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001473 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1474 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001475 return;
1476 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001477 if (ec)
1478 {
1479 BMCWEB_LOG_ERROR
1480 << "EventLogEntry (DBus) resp_handler got error " << ec;
1481 messages::internalError(asyncResp->res);
1482 return;
1483 }
1484 const uint32_t* id = nullptr;
1485 const uint64_t* timestamp = nullptr;
1486 const uint64_t* updateTimestamp = nullptr;
1487 const std::string* severity = nullptr;
1488 const std::string* message = nullptr;
1489 const std::string* filePath = nullptr;
1490 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001491
Ed Tanous002d39b2022-05-31 08:59:27 -07001492 for (const auto& propertyMap : resp)
1493 {
1494 if (propertyMap.first == "Id")
1495 {
1496 id = std::get_if<uint32_t>(&propertyMap.second);
1497 }
1498 else if (propertyMap.first == "Timestamp")
1499 {
1500 timestamp = std::get_if<uint64_t>(&propertyMap.second);
1501 }
1502 else if (propertyMap.first == "UpdateTimestamp")
1503 {
1504 updateTimestamp =
1505 std::get_if<uint64_t>(&propertyMap.second);
1506 }
1507 else if (propertyMap.first == "Severity")
1508 {
1509 severity = std::get_if<std::string>(&propertyMap.second);
1510 }
1511 else if (propertyMap.first == "Message")
1512 {
1513 message = std::get_if<std::string>(&propertyMap.second);
1514 }
1515 else if (propertyMap.first == "Resolved")
1516 {
1517 const bool* resolveptr =
1518 std::get_if<bool>(&propertyMap.second);
1519 if (resolveptr == nullptr)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001520 {
1521 messages::internalError(asyncResp->res);
1522 return;
1523 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001524 resolved = *resolveptr;
1525 }
1526 else if (propertyMap.first == "Path")
1527 {
1528 filePath = std::get_if<std::string>(&propertyMap.second);
1529 }
1530 }
1531 if (id == nullptr || message == nullptr || severity == nullptr ||
1532 timestamp == nullptr || updateTimestamp == nullptr)
1533 {
1534 messages::internalError(asyncResp->res);
1535 return;
1536 }
1537 asyncResp->res.jsonValue["@odata.type"] =
1538 "#LogEntry.v1_8_0.LogEntry";
1539 asyncResp->res.jsonValue["@odata.id"] =
1540 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1541 std::to_string(*id);
1542 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1543 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1544 asyncResp->res.jsonValue["Message"] = *message;
1545 asyncResp->res.jsonValue["Resolved"] = resolved;
1546 asyncResp->res.jsonValue["EntryType"] = "Event";
1547 asyncResp->res.jsonValue["Severity"] =
1548 translateSeverityDbusToRedfish(*severity);
1549 asyncResp->res.jsonValue["Created"] =
1550 crow::utility::getDateTimeUintMs(*timestamp);
1551 asyncResp->res.jsonValue["Modified"] =
1552 crow::utility::getDateTimeUintMs(*updateTimestamp);
1553 if (filePath != nullptr)
1554 {
1555 asyncResp->res.jsonValue["AdditionalDataURI"] =
1556 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1557 std::to_string(*id) + "/attachment";
1558 }
1559 },
1560 "xyz.openbmc_project.Logging",
1561 "/xyz/openbmc_project/logging/entry/" + entryID,
1562 "org.freedesktop.DBus.Properties", "GetAll", "");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001563 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001564
1565 BMCWEB_ROUTE(
1566 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001567 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001568 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001569 [&app](const crow::Request& req,
1570 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1571 const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001572 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001573 {
1574 return;
1575 }
1576 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001577
Ed Tanous002d39b2022-05-31 08:59:27 -07001578 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1579 resolved))
1580 {
1581 return;
1582 }
1583 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001584
Ed Tanous002d39b2022-05-31 08:59:27 -07001585 crow::connections::systemBus->async_method_call(
1586 [asyncResp, entryId](const boost::system::error_code ec) {
1587 if (ec)
1588 {
1589 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1590 messages::internalError(asyncResp->res);
1591 return;
1592 }
1593 },
1594 "xyz.openbmc_project.Logging",
1595 "/xyz/openbmc_project/logging/entry/" + entryId,
1596 "org.freedesktop.DBus.Properties", "Set",
1597 "xyz.openbmc_project.Logging.Entry", "Resolved",
1598 dbus::utility::DbusVariantType(*resolved));
1599 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001600
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001601 BMCWEB_ROUTE(
1602 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001603 .privileges(redfish::privileges::deleteLogEntry)
1604
Ed Tanous002d39b2022-05-31 08:59:27 -07001605 .methods(boost::beast::http::verb::delete_)(
1606 [&app](const crow::Request& req,
1607 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1608 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001609 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001610 {
1611 return;
1612 }
1613 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1614
1615 std::string entryID = param;
1616
1617 dbus::utility::escapePathForDbus(entryID);
1618
1619 // Process response from Logging service.
1620 auto respHandler =
1621 [asyncResp, entryID](const boost::system::error_code ec) {
1622 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1623 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001624 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001625 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001626 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001627 messages::resourceNotFound(asyncResp->res, "LogEntry",
1628 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001629 return;
1630 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001631 // TODO Handle for specific error code
1632 BMCWEB_LOG_ERROR
1633 << "EventLogEntry (DBus) doDelete respHandler got error "
1634 << ec;
1635 asyncResp->res.result(
1636 boost::beast::http::status::internal_server_error);
1637 return;
1638 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001639
Ed Tanous002d39b2022-05-31 08:59:27 -07001640 asyncResp->res.result(boost::beast::http::status::ok);
1641 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001642
Ed Tanous002d39b2022-05-31 08:59:27 -07001643 // Make call to Logging service to request Delete Log
1644 crow::connections::systemBus->async_method_call(
1645 respHandler, "xyz.openbmc_project.Logging",
1646 "/xyz/openbmc_project/logging/entry/" + entryID,
1647 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001648 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001649}
1650
1651inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001652{
George Liu0fda0f12021-11-16 10:06:17 +08001653 BMCWEB_ROUTE(
1654 app,
1655 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001656 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001657 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001658 [&app](const crow::Request& req,
1659 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1660 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001661 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001662 {
1663 return;
1664 }
1665 if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
1666 {
1667 asyncResp->res.result(boost::beast::http::status::bad_request);
1668 return;
1669 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001670
Ed Tanous002d39b2022-05-31 08:59:27 -07001671 std::string entryID = param;
1672 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001673
Ed Tanous002d39b2022-05-31 08:59:27 -07001674 crow::connections::systemBus->async_method_call(
1675 [asyncResp, entryID](const boost::system::error_code ec,
1676 const sdbusplus::message::unix_fd& unixfd) {
1677 if (ec.value() == EBADR)
1678 {
1679 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1680 entryID);
1681 return;
1682 }
1683 if (ec)
1684 {
1685 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1686 messages::internalError(asyncResp->res);
1687 return;
1688 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001689
Ed Tanous002d39b2022-05-31 08:59:27 -07001690 int fd = -1;
1691 fd = dup(unixfd);
1692 if (fd == -1)
1693 {
1694 messages::internalError(asyncResp->res);
1695 return;
1696 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001697
Ed Tanous002d39b2022-05-31 08:59:27 -07001698 long long int size = lseek(fd, 0, SEEK_END);
1699 if (size == -1)
1700 {
1701 messages::internalError(asyncResp->res);
1702 return;
1703 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001704
Ed Tanous002d39b2022-05-31 08:59:27 -07001705 // Arbitrary max size of 64kb
1706 constexpr int maxFileSize = 65536;
1707 if (size > maxFileSize)
1708 {
1709 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1710 << maxFileSize;
1711 messages::internalError(asyncResp->res);
1712 return;
1713 }
1714 std::vector<char> data(static_cast<size_t>(size));
1715 long long int rc = lseek(fd, 0, SEEK_SET);
1716 if (rc == -1)
1717 {
1718 messages::internalError(asyncResp->res);
1719 return;
1720 }
1721 rc = read(fd, data.data(), data.size());
1722 if ((rc == -1) || (rc != size))
1723 {
1724 messages::internalError(asyncResp->res);
1725 return;
1726 }
1727 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001728
Ed Tanous002d39b2022-05-31 08:59:27 -07001729 std::string_view strData(data.data(), data.size());
1730 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001731
Ed Tanous002d39b2022-05-31 08:59:27 -07001732 asyncResp->res.addHeader("Content-Type",
1733 "application/octet-stream");
1734 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1735 asyncResp->res.body() = std::move(output);
1736 },
1737 "xyz.openbmc_project.Logging",
1738 "/xyz/openbmc_project/logging/entry/" + entryID,
1739 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1740 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001741}
1742
Spencer Kub7028eb2021-10-26 15:27:35 +08001743constexpr const char* hostLoggerFolderPath = "/var/log/console";
1744
1745inline bool
1746 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1747 std::vector<std::filesystem::path>& hostLoggerFiles)
1748{
1749 std::error_code ec;
1750 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1751 if (ec)
1752 {
1753 BMCWEB_LOG_ERROR << ec.message();
1754 return false;
1755 }
1756 for (const std::filesystem::directory_entry& it : logPath)
1757 {
1758 std::string filename = it.path().filename();
1759 // Prefix of each log files is "log". Find the file and save the
1760 // path
1761 if (boost::starts_with(filename, "log"))
1762 {
1763 hostLoggerFiles.emplace_back(it.path());
1764 }
1765 }
1766 // As the log files rotate, they are appended with a ".#" that is higher for
1767 // the older logs. Since we start from oldest logs, sort the name in
1768 // descending order.
1769 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1770 AlphanumLess<std::string>());
1771
1772 return true;
1773}
1774
1775inline bool
1776 getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
Ed Tanousc937d2b2022-04-05 09:58:00 -07001777 uint64_t skip, uint64_t top,
Spencer Kub7028eb2021-10-26 15:27:35 +08001778 std::vector<std::string>& logEntries, size_t& logCount)
1779{
1780 GzFileReader logFile;
1781
1782 // Go though all log files and expose host logs.
1783 for (const std::filesystem::path& it : hostLoggerFiles)
1784 {
1785 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1786 {
1787 BMCWEB_LOG_ERROR << "fail to expose host logs";
1788 return false;
1789 }
1790 }
1791 // Get lastMessage from constructor by getter
1792 std::string lastMessage = logFile.getLastMessage();
1793 if (!lastMessage.empty())
1794 {
1795 logCount++;
1796 if (logCount > skip && logCount <= (skip + top))
1797 {
1798 logEntries.push_back(lastMessage);
1799 }
1800 }
1801 return true;
1802}
1803
1804inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1805 const std::string& msg,
1806 nlohmann::json& logEntryJson)
1807{
1808 // Fill in the log entry with the gathered data.
1809 logEntryJson = {
1810 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1811 {"@odata.id",
1812 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1813 logEntryID},
1814 {"Name", "Host Logger Entry"},
1815 {"Id", logEntryID},
1816 {"Message", msg},
1817 {"EntryType", "Oem"},
1818 {"Severity", "OK"},
1819 {"OemRecordFormat", "Host Logger Entry"}};
1820}
1821
1822inline void requestRoutesSystemHostLogger(App& app)
1823{
1824 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1825 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07001826 .methods(boost::beast::http::verb::get)(
1827 [&app](const crow::Request& req,
1828 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001829 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001830 {
1831 return;
1832 }
1833 asyncResp->res.jsonValue["@odata.id"] =
1834 "/redfish/v1/Systems/system/LogServices/HostLogger";
1835 asyncResp->res.jsonValue["@odata.type"] =
1836 "#LogService.v1_1_0.LogService";
1837 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1838 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1839 asyncResp->res.jsonValue["Id"] = "HostLogger";
1840 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1841 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1842 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001843}
1844
1845inline void requestRoutesSystemHostLoggerCollection(App& app)
1846{
1847 BMCWEB_ROUTE(app,
1848 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1849 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001850 .methods(boost::beast::http::verb::get)(
1851 [&app](const crow::Request& req,
1852 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1853 query_param::QueryCapabilities capabilities = {
1854 .canDelegateTop = true,
1855 .canDelegateSkip = true,
1856 };
1857 query_param::Query delegatedQuery;
1858 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001859 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001860 {
1861 return;
1862 }
1863 asyncResp->res.jsonValue["@odata.id"] =
1864 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1865 asyncResp->res.jsonValue["@odata.type"] =
1866 "#LogEntryCollection.LogEntryCollection";
1867 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1868 asyncResp->res.jsonValue["Description"] =
1869 "Collection of HostLogger Entries";
1870 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1871 logEntryArray = nlohmann::json::array();
1872 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001873
Ed Tanous002d39b2022-05-31 08:59:27 -07001874 std::vector<std::filesystem::path> hostLoggerFiles;
1875 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1876 {
1877 BMCWEB_LOG_ERROR << "fail to get host log file path";
1878 return;
1879 }
1880
1881 size_t logCount = 0;
1882 // This vector only store the entries we want to expose that
1883 // control by skip and top.
1884 std::vector<std::string> logEntries;
1885 if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1886 delegatedQuery.top, logEntries, logCount))
1887 {
1888 messages::internalError(asyncResp->res);
1889 return;
1890 }
1891 // If vector is empty, that means skip value larger than total
1892 // log count
1893 if (logEntries.empty())
1894 {
1895 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1896 return;
1897 }
1898 if (!logEntries.empty())
1899 {
1900 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08001901 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001902 logEntryArray.push_back({});
1903 nlohmann::json& hostLogEntry = logEntryArray.back();
1904 fillHostLoggerEntryJson(std::to_string(delegatedQuery.skip + i),
1905 logEntries[i], hostLogEntry);
George Liu0fda0f12021-11-16 10:06:17 +08001906 }
1907
Ed Tanous002d39b2022-05-31 08:59:27 -07001908 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1909 if (delegatedQuery.skip + delegatedQuery.top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08001910 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001911 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1912 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
1913 std::to_string(delegatedQuery.skip + delegatedQuery.top);
George Liu0fda0f12021-11-16 10:06:17 +08001914 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001915 }
George Liu0fda0f12021-11-16 10:06:17 +08001916 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001917}
1918
1919inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1920{
1921 BMCWEB_ROUTE(
1922 app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1923 .privileges(redfish::privileges::getLogEntry)
1924 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001925 [&app](const crow::Request& req,
1926 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1927 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001928 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001929 {
1930 return;
1931 }
1932 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08001933
Ed Tanous002d39b2022-05-31 08:59:27 -07001934 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08001935
Ed Tanous002d39b2022-05-31 08:59:27 -07001936 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1937 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08001938
Ed Tanous002d39b2022-05-31 08:59:27 -07001939 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
1940 if (ec == std::errc::invalid_argument)
1941 {
1942 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1943 return;
1944 }
1945 if (ec == std::errc::result_out_of_range)
1946 {
1947 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1948 return;
1949 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001950
Ed Tanous002d39b2022-05-31 08:59:27 -07001951 std::vector<std::filesystem::path> hostLoggerFiles;
1952 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1953 {
1954 BMCWEB_LOG_ERROR << "fail to get host log file path";
1955 return;
1956 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001957
Ed Tanous002d39b2022-05-31 08:59:27 -07001958 size_t logCount = 0;
1959 uint64_t top = 1;
1960 std::vector<std::string> logEntries;
1961 // We can get specific entry by skip and top. For example, if we
1962 // want to get nth entry, we can set skip = n-1 and top = 1 to
1963 // get that entry
1964 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
1965 logCount))
1966 {
1967 messages::internalError(asyncResp->res);
1968 return;
1969 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001970
Ed Tanous002d39b2022-05-31 08:59:27 -07001971 if (!logEntries.empty())
1972 {
1973 fillHostLoggerEntryJson(targetID, logEntries[0],
1974 asyncResp->res.jsonValue);
1975 return;
1976 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001977
Ed Tanous002d39b2022-05-31 08:59:27 -07001978 // Requested ID was not found
1979 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1980 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001981}
1982
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001983inline void requestRoutesBMCLogServiceCollection(App& app)
1984{
1985 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05001986 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001987 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001988 [&app](const crow::Request& req,
1989 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001990 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001991 {
1992 return;
1993 }
1994 // Collections don't include the static data added by SubRoute
1995 // because it has a duplicate entry for members
1996 asyncResp->res.jsonValue["@odata.type"] =
1997 "#LogServiceCollection.LogServiceCollection";
1998 asyncResp->res.jsonValue["@odata.id"] =
1999 "/redfish/v1/Managers/bmc/LogServices";
2000 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
2001 asyncResp->res.jsonValue["Description"] =
2002 "Collection of LogServices for this Manager";
2003 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
2004 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002005#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -07002006 logServiceArray.push_back(
2007 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002008#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002009#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
Ed Tanous002d39b2022-05-31 08:59:27 -07002010 logServiceArray.push_back(
2011 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002012#endif
Ed Tanous002d39b2022-05-31 08:59:27 -07002013 asyncResp->res.jsonValue["Members@odata.count"] =
2014 logServiceArray.size();
2015 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002016}
Ed Tanous1da66f72018-07-27 16:13:37 -07002017
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002018inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002019{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002020 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002021 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002022 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002023 [&app](const crow::Request& req,
2024 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002025 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002026 {
2027 return;
2028 }
2029 asyncResp->res.jsonValue["@odata.type"] =
2030 "#LogService.v1_1_0.LogService";
2031 asyncResp->res.jsonValue["@odata.id"] =
2032 "/redfish/v1/Managers/bmc/LogServices/Journal";
2033 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2034 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2035 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2036 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302037
Ed Tanous002d39b2022-05-31 08:59:27 -07002038 std::pair<std::string, std::string> redfishDateTimeOffset =
2039 crow::utility::getDateTimeOffsetNow();
2040 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2041 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2042 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302043
Ed Tanous002d39b2022-05-31 08:59:27 -07002044 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2045 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2046 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002047}
Jason M. Billse1f26342018-07-18 12:12:00 -07002048
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002049static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2050 sd_journal* journal,
2051 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002052{
2053 // Get the Log Entry contents
2054 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002055
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002056 std::string message;
2057 std::string_view syslogID;
2058 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2059 if (ret < 0)
2060 {
2061 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2062 << strerror(-ret);
2063 }
2064 if (!syslogID.empty())
2065 {
2066 message += std::string(syslogID) + ": ";
2067 }
2068
Ed Tanous39e77502019-03-04 17:35:53 -08002069 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002070 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002071 if (ret < 0)
2072 {
2073 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2074 return 1;
2075 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002076 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002077
2078 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002079 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002080 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002081 if (ret < 0)
2082 {
2083 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002084 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002085
2086 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002087 std::string entryTimeStr;
2088 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002089 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002090 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002091 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002092
2093 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002094 bmcJournalLogEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08002095 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002096 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2097 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002098 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002099 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002100 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002101 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002102 {"Severity", severity <= 2 ? "Critical"
2103 : severity <= 4 ? "Warning"
2104 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002105 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002106 {"Created", std::move(entryTimeStr)}};
2107 return 0;
2108}
2109
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002110inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002111{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002112 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002113 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002114 .methods(boost::beast::http::verb::get)(
2115 [&app](const crow::Request& req,
2116 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2117 query_param::QueryCapabilities capabilities = {
2118 .canDelegateTop = true,
2119 .canDelegateSkip = true,
2120 };
2121 query_param::Query delegatedQuery;
2122 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002123 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002124 {
2125 return;
2126 }
2127 // Collections don't include the static data added by SubRoute
2128 // because it has a duplicate entry for members
2129 asyncResp->res.jsonValue["@odata.type"] =
2130 "#LogEntryCollection.LogEntryCollection";
2131 asyncResp->res.jsonValue["@odata.id"] =
2132 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2133 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2134 asyncResp->res.jsonValue["Description"] =
2135 "Collection of BMC Journal Entries";
2136 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2137 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002138
Ed Tanous002d39b2022-05-31 08:59:27 -07002139 // Go through the journal and use the timestamp to create a
2140 // unique ID for each entry
2141 sd_journal* journalTmp = nullptr;
2142 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2143 if (ret < 0)
2144 {
2145 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2146 messages::internalError(asyncResp->res);
2147 return;
2148 }
2149 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2150 journalTmp, sd_journal_close);
2151 journalTmp = nullptr;
2152 uint64_t entryCount = 0;
2153 // Reset the unique ID on the first entry
2154 bool firstEntry = true;
2155 SD_JOURNAL_FOREACH(journal.get())
2156 {
2157 entryCount++;
2158 // Handle paging using skip (number of entries to skip from
2159 // the start) and top (number of entries to display)
2160 if (entryCount <= delegatedQuery.skip ||
2161 entryCount > delegatedQuery.skip + delegatedQuery.top)
George Liu0fda0f12021-11-16 10:06:17 +08002162 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002163 continue;
2164 }
2165
2166 std::string idStr;
2167 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2168 {
2169 continue;
2170 }
2171
2172 if (firstEntry)
2173 {
2174 firstEntry = false;
2175 }
2176
2177 logEntryArray.push_back({});
2178 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2179 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2180 bmcJournalLogEntry) != 0)
2181 {
George Liu0fda0f12021-11-16 10:06:17 +08002182 messages::internalError(asyncResp->res);
2183 return;
2184 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002185 }
2186 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2187 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
2188 {
2189 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2190 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
2191 std::to_string(delegatedQuery.skip + delegatedQuery.top);
2192 }
George Liu0fda0f12021-11-16 10:06:17 +08002193 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002194}
Jason M. Billse1f26342018-07-18 12:12:00 -07002195
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002196inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002197{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002198 BMCWEB_ROUTE(app,
2199 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002200 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002201 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002202 [&app](const crow::Request& req,
2203 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2204 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002205 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002206 {
2207 return;
2208 }
2209 // Convert the unique ID back to a timestamp to find the entry
2210 uint64_t ts = 0;
2211 uint64_t index = 0;
2212 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2213 {
2214 return;
2215 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002216
Ed Tanous002d39b2022-05-31 08:59:27 -07002217 sd_journal* journalTmp = nullptr;
2218 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2219 if (ret < 0)
2220 {
2221 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2222 messages::internalError(asyncResp->res);
2223 return;
2224 }
2225 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2226 journalTmp, sd_journal_close);
2227 journalTmp = nullptr;
2228 // Go to the timestamp in the log and move to the entry at the
2229 // index tracking the unique ID
2230 std::string idStr;
2231 bool firstEntry = true;
2232 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2233 if (ret < 0)
2234 {
2235 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2236 << strerror(-ret);
2237 messages::internalError(asyncResp->res);
2238 return;
2239 }
2240 for (uint64_t i = 0; i <= index; i++)
2241 {
2242 sd_journal_next(journal.get());
2243 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2244 {
2245 messages::internalError(asyncResp->res);
2246 return;
2247 }
2248 if (firstEntry)
2249 {
2250 firstEntry = false;
2251 }
2252 }
2253 // Confirm that the entry ID matches what was requested
2254 if (idStr != entryID)
2255 {
2256 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2257 return;
2258 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002259
Ed Tanous002d39b2022-05-31 08:59:27 -07002260 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2261 asyncResp->res.jsonValue) != 0)
2262 {
2263 messages::internalError(asyncResp->res);
2264 return;
2265 }
2266 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002267}
2268
2269inline void requestRoutesBMCDumpService(App& app)
2270{
2271 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002272 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002273 .methods(boost::beast::http::verb::get)(
2274 [&app](const crow::Request& req,
2275 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002276 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002277 {
2278 return;
2279 }
2280 asyncResp->res.jsonValue["@odata.id"] =
2281 "/redfish/v1/Managers/bmc/LogServices/Dump";
2282 asyncResp->res.jsonValue["@odata.type"] =
2283 "#LogService.v1_2_0.LogService";
2284 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2285 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2286 asyncResp->res.jsonValue["Id"] = "Dump";
2287 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302288
Ed Tanous002d39b2022-05-31 08:59:27 -07002289 std::pair<std::string, std::string> redfishDateTimeOffset =
2290 crow::utility::getDateTimeOffsetNow();
2291 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2292 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2293 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302294
Ed Tanous002d39b2022-05-31 08:59:27 -07002295 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2296 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2297 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2298 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog";
2299 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2300 ["target"] =
2301 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
George Liu0fda0f12021-11-16 10:06:17 +08002302 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002303}
2304
2305inline void requestRoutesBMCDumpEntryCollection(App& app)
2306{
2307
2308 /**
2309 * Functions triggers appropriate requests on DBus
2310 */
2311 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002312 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002313 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002314 [&app](const crow::Request& req,
2315 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002316 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002317 {
2318 return;
2319 }
2320 asyncResp->res.jsonValue["@odata.type"] =
2321 "#LogEntryCollection.LogEntryCollection";
2322 asyncResp->res.jsonValue["@odata.id"] =
2323 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2324 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
2325 asyncResp->res.jsonValue["Description"] =
2326 "Collection of BMC Dump Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002327
Ed Tanous002d39b2022-05-31 08:59:27 -07002328 getDumpEntryCollection(asyncResp, "BMC");
2329 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002330}
2331
2332inline void requestRoutesBMCDumpEntry(App& app)
2333{
2334 BMCWEB_ROUTE(app,
2335 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002336 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002337 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002338 [&app](const crow::Request& req,
2339 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2340 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002341 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002342 {
2343 return;
2344 }
Claire Weinanc7a6d662022-06-13 16:36:39 -07002345 getDumpEntryById(asyncResp, param, "BMC");
Ed Tanous002d39b2022-05-31 08:59:27 -07002346 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002347 BMCWEB_ROUTE(app,
2348 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002349 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002350 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002351 [&app](const crow::Request& req,
2352 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2353 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002354 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002355 {
2356 return;
2357 }
2358 deleteDumpEntry(asyncResp, param, "bmc");
2359 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002360}
2361
2362inline void requestRoutesBMCDumpCreate(App& app)
2363{
George Liu0fda0f12021-11-16 10:06:17 +08002364 BMCWEB_ROUTE(
2365 app,
2366 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002367 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002368 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002369 [&app](const crow::Request& req,
2370 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002371 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002372 {
2373 return;
2374 }
2375 createDump(asyncResp, req, "BMC");
2376 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002377}
2378
2379inline void requestRoutesBMCDumpClear(App& app)
2380{
George Liu0fda0f12021-11-16 10:06:17 +08002381 BMCWEB_ROUTE(
2382 app,
2383 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002384 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002385 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002386 [&app](const crow::Request& req,
2387 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002388 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002389 {
2390 return;
2391 }
2392 clearDump(asyncResp, "BMC");
2393 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002394}
2395
2396inline void requestRoutesSystemDumpService(App& app)
2397{
2398 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002399 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002400 .methods(boost::beast::http::verb::get)(
2401 [&app](const crow::Request& req,
2402 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002403 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002404 {
2405 return;
2406 }
2407 asyncResp->res.jsonValue["@odata.id"] =
2408 "/redfish/v1/Systems/system/LogServices/Dump";
2409 asyncResp->res.jsonValue["@odata.type"] =
2410 "#LogService.v1_2_0.LogService";
2411 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2412 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2413 asyncResp->res.jsonValue["Id"] = "Dump";
2414 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302415
Ed Tanous002d39b2022-05-31 08:59:27 -07002416 std::pair<std::string, std::string> redfishDateTimeOffset =
2417 crow::utility::getDateTimeOffsetNow();
2418 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2419 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2420 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302421
Ed Tanous002d39b2022-05-31 08:59:27 -07002422 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2423 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2424 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2425 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog";
Ed Tanous14766872022-03-15 10:44:42 -07002426
Ed Tanous002d39b2022-05-31 08:59:27 -07002427 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2428 ["target"] =
2429 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
Ed Tanous45ca1b82022-03-25 13:07:27 -07002430 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002431}
2432
2433inline void requestRoutesSystemDumpEntryCollection(App& app)
2434{
2435
2436 /**
2437 * Functions triggers appropriate requests on DBus
2438 */
Asmitha Karunanithib2a32892021-07-13 11:56:15 -05002439 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002440 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002441 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002442 [&app](const crow::Request& req,
2443 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002444 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002445 {
2446 return;
2447 }
2448 asyncResp->res.jsonValue["@odata.type"] =
2449 "#LogEntryCollection.LogEntryCollection";
2450 asyncResp->res.jsonValue["@odata.id"] =
2451 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2452 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2453 asyncResp->res.jsonValue["Description"] =
2454 "Collection of System Dump Entries";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002455
Ed Tanous002d39b2022-05-31 08:59:27 -07002456 getDumpEntryCollection(asyncResp, "System");
2457 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002458}
2459
2460inline void requestRoutesSystemDumpEntry(App& app)
2461{
2462 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002463 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002464 .privileges(redfish::privileges::getLogEntry)
2465
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002466 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002467 [&app](const crow::Request& req,
2468 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2469 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002470 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Claire Weinanc7a6d662022-06-13 16:36:39 -07002471 {
2472 return;
2473 }
2474 getDumpEntryById(asyncResp, param, "System");
Ed Tanous002d39b2022-05-31 08:59:27 -07002475 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002476
2477 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002478 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002479 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002480 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002481 [&app](const crow::Request& req,
2482 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2483 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002484 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002485 {
2486 return;
2487 }
2488 deleteDumpEntry(asyncResp, param, "system");
2489 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002490}
2491
2492inline void requestRoutesSystemDumpCreate(App& app)
2493{
George Liu0fda0f12021-11-16 10:06:17 +08002494 BMCWEB_ROUTE(
2495 app,
2496 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002497 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002498 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002499 [&app](const crow::Request& req,
2500 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002501 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002502 {
2503 return;
2504 }
2505 createDump(asyncResp, req, "System");
2506 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002507}
2508
2509inline void requestRoutesSystemDumpClear(App& app)
2510{
George Liu0fda0f12021-11-16 10:06:17 +08002511 BMCWEB_ROUTE(
2512 app,
2513 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002514 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002515 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002516 [&app](const crow::Request& req,
2517 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002518
Ed Tanous45ca1b82022-03-25 13:07:27 -07002519 {
Carson Labrado3ba00072022-06-06 19:40:56 +00002520 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002521 {
2522 return;
2523 }
2524 clearDump(asyncResp, "System");
2525 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002526}
2527
2528inline void requestRoutesCrashdumpService(App& app)
2529{
2530 // Note: Deviated from redfish privilege registry for GET & HEAD
2531 // method for security reasons.
2532 /**
2533 * Functions triggers appropriate requests on DBus
2534 */
2535 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002536 // This is incorrect, should be:
2537 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002538 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002539 .methods(boost::beast::http::verb::get)(
2540 [&app](const crow::Request& req,
2541 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002542 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002543 {
2544 return;
2545 }
2546 // Copy over the static data to include the entries added by
2547 // SubRoute
2548 asyncResp->res.jsonValue["@odata.id"] =
2549 "/redfish/v1/Systems/system/LogServices/Crashdump";
2550 asyncResp->res.jsonValue["@odata.type"] =
2551 "#LogService.v1_2_0.LogService";
2552 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2553 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2554 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2555 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2556 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302557
Ed Tanous002d39b2022-05-31 08:59:27 -07002558 std::pair<std::string, std::string> redfishDateTimeOffset =
2559 crow::utility::getDateTimeOffsetNow();
2560 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2561 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2562 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302563
Ed Tanous002d39b2022-05-31 08:59:27 -07002564 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2565 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2566 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2567 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2568 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2569 ["target"] =
2570 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002571 });
2572}
2573
2574void inline requestRoutesCrashdumpClear(App& app)
2575{
George Liu0fda0f12021-11-16 10:06:17 +08002576 BMCWEB_ROUTE(
2577 app,
2578 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002579 // This is incorrect, should be:
2580 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002581 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002582 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002583 [&app](const crow::Request& req,
2584 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002585 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002586 {
2587 return;
2588 }
2589 crow::connections::systemBus->async_method_call(
2590 [asyncResp](const boost::system::error_code ec,
2591 const std::string&) {
2592 if (ec)
2593 {
2594 messages::internalError(asyncResp->res);
2595 return;
2596 }
2597 messages::success(asyncResp->res);
2598 },
2599 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2600 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002601}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002602
zhanghch058d1b46d2021-04-01 11:18:24 +08002603static void
2604 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2605 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002606{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002607 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002608 [asyncResp, logID,
2609 &logEntryJson](const boost::system::error_code ec,
2610 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002611 if (ec)
2612 {
2613 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2614 if (ec.value() ==
2615 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002616 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002617 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002618 }
2619 else
2620 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002621 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002622 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002623 return;
2624 }
2625
2626 std::string timestamp{};
2627 std::string filename{};
2628 std::string logfile{};
2629 parseCrashdumpParameters(params, filename, timestamp, logfile);
2630
2631 if (filename.empty() || timestamp.empty())
2632 {
2633 messages::resourceMissingAtURI(asyncResp->res,
2634 crow::utility::urlFromPieces(logID));
2635 return;
2636 }
2637
2638 std::string crashdumpURI =
2639 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2640 logID + "/" + filename;
2641 nlohmann::json logEntry = {
2642 {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
2643 {"@odata.id",
2644 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2645 logID},
2646 {"Name", "CPU Crashdump"},
2647 {"Id", logID},
2648 {"EntryType", "Oem"},
2649 {"AdditionalDataURI", std::move(crashdumpURI)},
2650 {"DiagnosticDataType", "OEM"},
2651 {"OEMDiagnosticDataType", "PECICrashdump"},
2652 {"Created", std::move(timestamp)}};
2653
2654 // If logEntryJson references an array of LogEntry resources
2655 // ('Members' list), then push this as a new entry, otherwise set it
2656 // directly
2657 if (logEntryJson.is_array())
2658 {
2659 logEntryJson.push_back(logEntry);
2660 asyncResp->res.jsonValue["Members@odata.count"] =
2661 logEntryJson.size();
2662 }
2663 else
2664 {
2665 logEntryJson = logEntry;
2666 }
2667 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002668 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002669 std::move(getStoredLogCallback), crashdumpObject,
2670 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002671 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002672}
2673
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002674inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002675{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002676 // Note: Deviated from redfish privilege registry for GET & HEAD
2677 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002678 /**
2679 * Functions triggers appropriate requests on DBus
2680 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002681 BMCWEB_ROUTE(app,
2682 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002683 // This is incorrect, should be.
2684 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002685 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002686 .methods(boost::beast::http::verb::get)(
2687 [&app](const crow::Request& req,
2688 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002689 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002690 {
2691 return;
2692 }
2693 crow::connections::systemBus->async_method_call(
2694 [asyncResp](const boost::system::error_code ec,
2695 const std::vector<std::string>& resp) {
2696 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002697 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002698 if (ec.value() !=
2699 boost::system::errc::no_such_file_or_directory)
2700 {
2701 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2702 << ec.message();
2703 messages::internalError(asyncResp->res);
2704 return;
2705 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002706 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002707 asyncResp->res.jsonValue["@odata.type"] =
2708 "#LogEntryCollection.LogEntryCollection";
2709 asyncResp->res.jsonValue["@odata.id"] =
2710 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2711 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
2712 asyncResp->res.jsonValue["Description"] =
2713 "Collection of Crashdump Entries";
2714 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
2715 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002716
Ed Tanous002d39b2022-05-31 08:59:27 -07002717 for (const std::string& path : resp)
2718 {
2719 const sdbusplus::message::object_path objPath(path);
2720 // Get the log ID
2721 std::string logID = objPath.filename();
2722 if (logID.empty())
2723 {
2724 continue;
2725 }
2726 // Add the log entry to the array
2727 logCrashdumpEntry(asyncResp, logID,
2728 asyncResp->res.jsonValue["Members"]);
2729 }
2730 },
2731 "xyz.openbmc_project.ObjectMapper",
2732 "/xyz/openbmc_project/object_mapper",
2733 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
2734 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002735 });
2736}
Ed Tanous1da66f72018-07-27 16:13:37 -07002737
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002738inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002739{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002740 // Note: Deviated from redfish privilege registry for GET & HEAD
2741 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002742
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002743 BMCWEB_ROUTE(
2744 app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002745 // this is incorrect, should be
2746 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07002747 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002748 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002749 [&app](const crow::Request& req,
2750 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2751 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002752 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002753 {
2754 return;
2755 }
2756 const std::string& logID = param;
2757 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2758 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002759}
Ed Tanous1da66f72018-07-27 16:13:37 -07002760
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002761inline void requestRoutesCrashdumpFile(App& app)
2762{
2763 // Note: Deviated from redfish privilege registry for GET & HEAD
2764 // method for security reasons.
2765 BMCWEB_ROUTE(
2766 app,
2767 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002768 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002769 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002770 [&app](const crow::Request& req,
2771 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2772 const std::string& logID, const std::string& fileName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002773 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002774 {
2775 return;
2776 }
2777 auto getStoredLogCallback =
2778 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
2779 const boost::system::error_code ec,
2780 const std::vector<
2781 std::pair<std::string, dbus::utility::DbusVariantType>>&
2782 resp) {
2783 if (ec)
2784 {
2785 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2786 messages::internalError(asyncResp->res);
2787 return;
2788 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002789
Ed Tanous002d39b2022-05-31 08:59:27 -07002790 std::string dbusFilename{};
2791 std::string dbusTimestamp{};
2792 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002793
Ed Tanous002d39b2022-05-31 08:59:27 -07002794 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
2795 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002796
Ed Tanous002d39b2022-05-31 08:59:27 -07002797 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2798 dbusFilepath.empty())
2799 {
2800 messages::resourceMissingAtURI(asyncResp->res, url);
2801 return;
2802 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002803
Ed Tanous002d39b2022-05-31 08:59:27 -07002804 // Verify the file name parameter is correct
2805 if (fileName != dbusFilename)
2806 {
2807 messages::resourceMissingAtURI(asyncResp->res, url);
2808 return;
2809 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002810
Ed Tanous002d39b2022-05-31 08:59:27 -07002811 if (!std::filesystem::exists(dbusFilepath))
2812 {
2813 messages::resourceMissingAtURI(asyncResp->res, url);
2814 return;
2815 }
2816 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
2817 asyncResp->res.body() =
2818 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002819
Ed Tanous002d39b2022-05-31 08:59:27 -07002820 // Configure this to be a file download when accessed
2821 // from a browser
2822 asyncResp->res.addHeader("Content-Disposition", "attachment");
2823 };
2824 crow::connections::systemBus->async_method_call(
2825 std::move(getStoredLogCallback), crashdumpObject,
2826 crashdumpPath + std::string("/") + logID,
2827 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
2828 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002829}
2830
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002831enum class OEMDiagnosticType
2832{
2833 onDemand,
2834 telemetry,
2835 invalid,
2836};
2837
Ed Tanousf7725d72022-03-07 12:46:00 -08002838inline OEMDiagnosticType
2839 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002840{
2841 if (oemDiagStr == "OnDemand")
2842 {
2843 return OEMDiagnosticType::onDemand;
2844 }
2845 if (oemDiagStr == "Telemetry")
2846 {
2847 return OEMDiagnosticType::telemetry;
2848 }
2849
2850 return OEMDiagnosticType::invalid;
2851}
2852
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002853inline void requestRoutesCrashdumpCollect(App& app)
2854{
2855 // Note: Deviated from redfish privilege registry for GET & HEAD
2856 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08002857 BMCWEB_ROUTE(
2858 app,
2859 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002860 // The below is incorrect; Should be ConfigureManager
2861 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002862 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002863 .methods(boost::beast::http::verb::post)(
2864 [&app](const crow::Request& req,
2865 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002866 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002867 {
2868 return;
2869 }
2870 std::string diagnosticDataType;
2871 std::string oemDiagnosticDataType;
2872 if (!redfish::json_util::readJsonAction(
2873 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2874 "OEMDiagnosticDataType", oemDiagnosticDataType))
2875 {
2876 return;
2877 }
2878
2879 if (diagnosticDataType != "OEM")
2880 {
2881 BMCWEB_LOG_ERROR
2882 << "Only OEM DiagnosticDataType supported for Crashdump";
2883 messages::actionParameterValueFormatError(
2884 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2885 "CollectDiagnosticData");
2886 return;
2887 }
2888
2889 OEMDiagnosticType oemDiagType =
2890 getOEMDiagnosticType(oemDiagnosticDataType);
2891
2892 std::string iface;
2893 std::string method;
2894 std::string taskMatchStr;
2895 if (oemDiagType == OEMDiagnosticType::onDemand)
2896 {
2897 iface = crashdumpOnDemandInterface;
2898 method = "GenerateOnDemandLog";
2899 taskMatchStr = "type='signal',"
2900 "interface='org.freedesktop.DBus.Properties',"
2901 "member='PropertiesChanged',"
2902 "arg0namespace='com.intel.crashdump'";
2903 }
2904 else if (oemDiagType == OEMDiagnosticType::telemetry)
2905 {
2906 iface = crashdumpTelemetryInterface;
2907 method = "GenerateTelemetryLog";
2908 taskMatchStr = "type='signal',"
2909 "interface='org.freedesktop.DBus.Properties',"
2910 "member='PropertiesChanged',"
2911 "arg0namespace='com.intel.crashdump'";
2912 }
2913 else
2914 {
2915 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2916 << oemDiagnosticDataType;
2917 messages::actionParameterValueFormatError(
2918 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
2919 "CollectDiagnosticData");
2920 return;
2921 }
2922
2923 auto collectCrashdumpCallback =
2924 [asyncResp, payload(task::Payload(req)),
2925 taskMatchStr](const boost::system::error_code ec,
2926 const std::string&) mutable {
2927 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002928 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002929 if (ec.value() == boost::system::errc::operation_not_supported)
2930 {
2931 messages::resourceInStandby(asyncResp->res);
2932 }
2933 else if (ec.value() ==
2934 boost::system::errc::device_or_resource_busy)
2935 {
2936 messages::serviceTemporarilyUnavailable(asyncResp->res,
2937 "60");
2938 }
2939 else
2940 {
2941 messages::internalError(asyncResp->res);
2942 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002943 return;
2944 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002945 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
2946 [](boost::system::error_code err, sdbusplus::message::message&,
2947 const std::shared_ptr<task::TaskData>& taskData) {
2948 if (!err)
2949 {
2950 taskData->messages.emplace_back(messages::taskCompletedOK(
2951 std::to_string(taskData->index)));
2952 taskData->state = "Completed";
2953 }
2954 return task::completed;
2955 },
2956 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07002957
Ed Tanous002d39b2022-05-31 08:59:27 -07002958 task->startTimer(std::chrono::minutes(5));
2959 task->populateResp(asyncResp->res);
2960 task->payload.emplace(std::move(payload));
2961 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002962
Ed Tanous002d39b2022-05-31 08:59:27 -07002963 crow::connections::systemBus->async_method_call(
2964 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
2965 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002966 });
2967}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07002968
Andrew Geisslercb92c032018-08-17 07:56:14 -07002969/**
2970 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
2971 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002972inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07002973{
Andrew Geisslercb92c032018-08-17 07:56:14 -07002974 /**
2975 * Function handles POST method request.
2976 * The Clear Log actions does not require any parameter.The action deletes
2977 * all entries found in the Entries collection for this Log Service.
2978 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07002979
George Liu0fda0f12021-11-16 10:06:17 +08002980 BMCWEB_ROUTE(
2981 app,
2982 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002983 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002984 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002985 [&app](const crow::Request& req,
2986 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002987 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002988 {
2989 return;
2990 }
2991 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07002992
Ed Tanous002d39b2022-05-31 08:59:27 -07002993 // Process response from Logging service.
2994 auto respHandler = [asyncResp](const boost::system::error_code ec) {
2995 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
2996 if (ec)
2997 {
2998 // TODO Handle for specific error code
2999 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3000 asyncResp->res.result(
3001 boost::beast::http::status::internal_server_error);
3002 return;
3003 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003004
Ed Tanous002d39b2022-05-31 08:59:27 -07003005 asyncResp->res.result(boost::beast::http::status::no_content);
3006 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003007
Ed Tanous002d39b2022-05-31 08:59:27 -07003008 // Make call to Logging service to request Clear Log
3009 crow::connections::systemBus->async_method_call(
3010 respHandler, "xyz.openbmc_project.Logging",
3011 "/xyz/openbmc_project/logging",
3012 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3013 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003014}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003015
3016/****************************************************
3017 * Redfish PostCode interfaces
3018 * using DBUS interface: getPostCodesTS
3019 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003020inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003021{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003022 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003023 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003024 .methods(boost::beast::http::verb::get)(
3025 [&app](const crow::Request& req,
3026 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003027 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003028 {
3029 return;
3030 }
Ed Tanous14766872022-03-15 10:44:42 -07003031
Ed Tanous002d39b2022-05-31 08:59:27 -07003032 asyncResp->res.jsonValue["@odata.id"] =
3033 "/redfish/v1/Systems/system/LogServices/PostCodes";
3034 asyncResp->res.jsonValue["@odata.type"] =
3035 "#LogService.v1_1_0.LogService";
3036 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3037 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3038 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3039 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3040 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3041 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303042
Ed Tanous002d39b2022-05-31 08:59:27 -07003043 std::pair<std::string, std::string> redfishDateTimeOffset =
3044 crow::utility::getDateTimeOffsetNow();
3045 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3046 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3047 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303048
Ed Tanous002d39b2022-05-31 08:59:27 -07003049 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3050 {"target",
3051 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003052 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003053}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003054
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003055inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003056{
George Liu0fda0f12021-11-16 10:06:17 +08003057 BMCWEB_ROUTE(
3058 app,
3059 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003060 // The following privilege is incorrect; It should be ConfigureManager
3061 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003062 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003063 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003064 [&app](const crow::Request& req,
3065 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003066 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003067 {
3068 return;
3069 }
3070 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003071
Ed Tanous002d39b2022-05-31 08:59:27 -07003072 // Make call to post-code service to request clear all
3073 crow::connections::systemBus->async_method_call(
3074 [asyncResp](const boost::system::error_code ec) {
3075 if (ec)
3076 {
3077 // TODO Handle for specific error code
3078 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3079 << ec;
3080 asyncResp->res.result(
3081 boost::beast::http::status::internal_server_error);
3082 messages::internalError(asyncResp->res);
3083 return;
3084 }
3085 },
3086 "xyz.openbmc_project.State.Boot.PostCode0",
3087 "/xyz/openbmc_project/State/Boot/PostCode0",
3088 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3089 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003090}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003091
3092static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003093 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303094 const boost::container::flat_map<
3095 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003096 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3097 const uint64_t skip = 0, const uint64_t top = 0)
3098{
3099 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003100 const registries::Message* message =
3101 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003102
3103 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003104 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003105
3106 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303107 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3108 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003109 {
3110 currentCodeIndex++;
3111 std::string postcodeEntryID =
3112 "B" + std::to_string(bootIndex) + "-" +
3113 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3114
3115 uint64_t usecSinceEpoch = code.first;
3116 uint64_t usTimeOffset = 0;
3117
3118 if (1 == currentCodeIndex)
3119 { // already incremented
3120 firstCodeTimeUs = code.first;
3121 }
3122 else
3123 {
3124 usTimeOffset = code.first - firstCodeTimeUs;
3125 }
3126
3127 // skip if no specific codeIndex is specified and currentCodeIndex does
3128 // not fall between top and skip
3129 if ((codeIndex == 0) &&
3130 (currentCodeIndex <= skip || currentCodeIndex > top))
3131 {
3132 continue;
3133 }
3134
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003135 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003136 // currentIndex
3137 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3138 {
3139 // This is done for simplicity. 1st entry is needed to calculate
3140 // time offset. To improve efficiency, one can get to the entry
3141 // directly (possibly with flatmap's nth method)
3142 continue;
3143 }
3144
3145 // currentCodeIndex is within top and skip or equal to specified code
3146 // index
3147
3148 // Get the Created time from the timestamp
3149 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003150 entryTimeStr =
3151 crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003152
3153 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3154 std::ostringstream hexCode;
3155 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303156 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003157 std::ostringstream timeOffsetStr;
3158 // Set Fixed -Point Notation
3159 timeOffsetStr << std::fixed;
3160 // Set precision to 4 digits
3161 timeOffsetStr << std::setprecision(4);
3162 // Add double to stream
3163 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3164 std::vector<std::string> messageArgs = {
3165 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3166
3167 // Get MessageArgs template from message registry
3168 std::string msg;
3169 if (message != nullptr)
3170 {
3171 msg = message->message;
3172
3173 // fill in this post code value
3174 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003175 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003176 {
3177 std::string argStr = "%" + std::to_string(++i);
3178 size_t argPos = msg.find(argStr);
3179 if (argPos != std::string::npos)
3180 {
3181 msg.replace(argPos, argStr.length(), messageArg);
3182 }
3183 }
3184 }
3185
Tim Leed4342a92020-04-27 11:47:58 +08003186 // Get Severity template from message registry
3187 std::string severity;
3188 if (message != nullptr)
3189 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003190 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003191 }
3192
ZhikuiRena3316fc2020-01-29 14:58:08 -08003193 // add to AsyncResp
3194 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003195 nlohmann::json& bmcLogEntry = logEntryArray.back();
George Liu0fda0f12021-11-16 10:06:17 +08003196 bmcLogEntry = {
3197 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
3198 {"@odata.id",
3199 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3200 postcodeEntryID},
3201 {"Name", "POST Code Log Entry"},
3202 {"Id", postcodeEntryID},
3203 {"Message", std::move(msg)},
3204 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3205 {"MessageArgs", std::move(messageArgs)},
3206 {"EntryType", "Event"},
3207 {"Severity", std::move(severity)},
3208 {"Created", entryTimeStr}};
George Liu647b3cd2021-07-05 12:43:56 +08003209 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3210 {
3211 bmcLogEntry["AdditionalDataURI"] =
3212 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3213 postcodeEntryID + "/attachment";
3214 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003215 }
3216}
3217
zhanghch058d1b46d2021-04-01 11:18:24 +08003218static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003219 const uint16_t bootIndex,
3220 const uint64_t codeIndex)
3221{
3222 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303223 [aResp, bootIndex,
3224 codeIndex](const boost::system::error_code ec,
3225 const boost::container::flat_map<
3226 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3227 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003228 if (ec)
3229 {
3230 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3231 messages::internalError(aResp->res);
3232 return;
3233 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003234
Ed Tanous002d39b2022-05-31 08:59:27 -07003235 // skip the empty postcode boots
3236 if (postcode.empty())
3237 {
3238 return;
3239 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003240
Ed Tanous002d39b2022-05-31 08:59:27 -07003241 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003242
Ed Tanous002d39b2022-05-31 08:59:27 -07003243 aResp->res.jsonValue["Members@odata.count"] =
3244 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003245 },
Jonathan Doman15124762021-01-07 17:54:17 -08003246 "xyz.openbmc_project.State.Boot.PostCode0",
3247 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003248 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3249 bootIndex);
3250}
3251
zhanghch058d1b46d2021-04-01 11:18:24 +08003252static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003253 const uint16_t bootIndex,
3254 const uint16_t bootCount,
3255 const uint64_t entryCount, const uint64_t skip,
3256 const uint64_t top)
3257{
3258 crow::connections::systemBus->async_method_call(
3259 [aResp, bootIndex, bootCount, entryCount, skip,
3260 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303261 const boost::container::flat_map<
3262 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3263 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003264 if (ec)
3265 {
3266 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3267 messages::internalError(aResp->res);
3268 return;
3269 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003270
Ed Tanous002d39b2022-05-31 08:59:27 -07003271 uint64_t endCount = entryCount;
3272 if (!postcode.empty())
3273 {
3274 endCount = entryCount + postcode.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003275
Ed Tanous002d39b2022-05-31 08:59:27 -07003276 if ((skip < endCount) && ((top + skip) > entryCount))
ZhikuiRena3316fc2020-01-29 14:58:08 -08003277 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003278 uint64_t thisBootSkip = std::max(skip, entryCount) - entryCount;
3279 uint64_t thisBootTop =
3280 std::min(top + skip, endCount) - entryCount;
3281
3282 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3283 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003284 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003285 aResp->res.jsonValue["Members@odata.count"] = endCount;
3286 }
3287
3288 // continue to previous bootIndex
3289 if (bootIndex < bootCount)
3290 {
3291 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3292 bootCount, endCount, skip, top);
3293 }
3294 else
3295 {
3296 aResp->res.jsonValue["Members@odata.nextLink"] =
3297 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3298 std::to_string(skip + top);
3299 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003300 },
Jonathan Doman15124762021-01-07 17:54:17 -08003301 "xyz.openbmc_project.State.Boot.PostCode0",
3302 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003303 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3304 bootIndex);
3305}
3306
zhanghch058d1b46d2021-04-01 11:18:24 +08003307static void
3308 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3309 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003310{
3311 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003312 sdbusplus::asio::getProperty<uint16_t>(
3313 *crow::connections::systemBus,
3314 "xyz.openbmc_project.State.Boot.PostCode0",
3315 "/xyz/openbmc_project/State/Boot/PostCode0",
3316 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3317 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3318 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003319 if (ec)
3320 {
3321 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3322 messages::internalError(aResp->res);
3323 return;
3324 }
3325 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003326 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003327}
3328
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003329inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003330{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003331 BMCWEB_ROUTE(app,
3332 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003333 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003334 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003335 [&app](const crow::Request& req,
3336 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003337 query_param::QueryCapabilities capabilities = {
3338 .canDelegateTop = true,
3339 .canDelegateSkip = true,
3340 };
3341 query_param::Query delegatedQuery;
3342 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003343 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003344 {
3345 return;
3346 }
3347 asyncResp->res.jsonValue["@odata.type"] =
3348 "#LogEntryCollection.LogEntryCollection";
3349 asyncResp->res.jsonValue["@odata.id"] =
3350 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3351 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3352 asyncResp->res.jsonValue["Description"] =
3353 "Collection of POST Code Log Entries";
3354 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3355 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003356
Ed Tanous002d39b2022-05-31 08:59:27 -07003357 getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3358 delegatedQuery.top);
3359 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003360}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003361
George Liu647b3cd2021-07-05 12:43:56 +08003362/**
3363 * @brief Parse post code ID and get the current value and index value
3364 * eg: postCodeID=B1-2, currentValue=1, index=2
3365 *
3366 * @param[in] postCodeID Post Code ID
3367 * @param[out] currentValue Current value
3368 * @param[out] index Index value
3369 *
3370 * @return bool true if the parsing is successful, false the parsing fails
3371 */
3372inline static bool parsePostCode(const std::string& postCodeID,
3373 uint64_t& currentValue, uint16_t& index)
3374{
3375 std::vector<std::string> split;
3376 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3377 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3378 {
3379 return false;
3380 }
3381
Ed Tanousca45aa32022-01-07 09:28:45 -08003382 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003383 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003384 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003385 const char* end = split[0].data() + split[0].size();
3386 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3387
3388 if (ptrIndex != end || ecIndex != std::errc())
3389 {
3390 return false;
3391 }
3392
3393 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003394
3395 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003396 end = split[1].data() + split[1].size();
3397 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003398
Ed Tanousdcf2ebc2022-01-25 10:07:45 -08003399 return ptrValue == end && ecValue != std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003400}
3401
3402inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3403{
George Liu0fda0f12021-11-16 10:06:17 +08003404 BMCWEB_ROUTE(
3405 app,
3406 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003407 .privileges(redfish::privileges::getLogEntry)
3408 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003409 [&app](const crow::Request& req,
3410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3411 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003412 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003413 {
3414 return;
3415 }
3416 if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
3417 {
3418 asyncResp->res.result(boost::beast::http::status::bad_request);
3419 return;
3420 }
George Liu647b3cd2021-07-05 12:43:56 +08003421
Ed Tanous002d39b2022-05-31 08:59:27 -07003422 uint64_t currentValue = 0;
3423 uint16_t index = 0;
3424 if (!parsePostCode(postCodeID, currentValue, index))
3425 {
3426 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3427 return;
3428 }
George Liu647b3cd2021-07-05 12:43:56 +08003429
Ed Tanous002d39b2022-05-31 08:59:27 -07003430 crow::connections::systemBus->async_method_call(
3431 [asyncResp, postCodeID, currentValue](
3432 const boost::system::error_code ec,
3433 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3434 postcodes) {
3435 if (ec.value() == EBADR)
3436 {
3437 messages::resourceNotFound(asyncResp->res, "LogEntry",
3438 postCodeID);
3439 return;
3440 }
3441 if (ec)
3442 {
3443 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3444 messages::internalError(asyncResp->res);
3445 return;
3446 }
George Liu647b3cd2021-07-05 12:43:56 +08003447
Ed Tanous002d39b2022-05-31 08:59:27 -07003448 size_t value = static_cast<size_t>(currentValue) - 1;
3449 if (value == std::string::npos || postcodes.size() < currentValue)
3450 {
3451 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3452 messages::resourceNotFound(asyncResp->res, "LogEntry",
3453 postCodeID);
3454 return;
3455 }
George Liu647b3cd2021-07-05 12:43:56 +08003456
Ed Tanous002d39b2022-05-31 08:59:27 -07003457 const auto& [tID, c] = postcodes[value];
3458 if (c.empty())
3459 {
3460 BMCWEB_LOG_INFO << "No found post code data";
3461 messages::resourceNotFound(asyncResp->res, "LogEntry",
3462 postCodeID);
3463 return;
3464 }
3465 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3466 const char* d = reinterpret_cast<const char*>(c.data());
3467 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003468
Ed Tanous002d39b2022-05-31 08:59:27 -07003469 asyncResp->res.addHeader("Content-Type",
3470 "application/octet-stream");
3471 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
3472 asyncResp->res.body() = crow::utility::base64encode(strData);
3473 },
3474 "xyz.openbmc_project.State.Boot.PostCode0",
3475 "/xyz/openbmc_project/State/Boot/PostCode0",
3476 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3477 });
George Liu647b3cd2021-07-05 12:43:56 +08003478}
3479
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003480inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003481{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003482 BMCWEB_ROUTE(
3483 app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003484 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003485 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003486 [&app](const crow::Request& req,
3487 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3488 const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003489 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003490 {
3491 return;
3492 }
3493 uint16_t bootIndex = 0;
3494 uint64_t codeIndex = 0;
3495 if (!parsePostCode(targetID, codeIndex, bootIndex))
3496 {
3497 // Requested ID was not found
3498 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
3499 return;
3500 }
3501 if (bootIndex == 0 || codeIndex == 0)
3502 {
3503 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3504 << targetID;
3505 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003506
Ed Tanous002d39b2022-05-31 08:59:27 -07003507 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
3508 asyncResp->res.jsonValue["@odata.id"] =
3509 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3510 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3511 asyncResp->res.jsonValue["Description"] =
3512 "Collection of POST Code Log Entries";
3513 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3514 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003515
Ed Tanous002d39b2022-05-31 08:59:27 -07003516 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3517 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003518}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003519
Ed Tanous1da66f72018-07-27 16:13:37 -07003520} // namespace redfish