blob: e4846499c082c11760cf6ee0271d04e318373470 [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
Nan Zhou21ab4042022-06-26 23:07:40 +0000328static std::string getDumpEntriesPath(const std::string& dumpType)
Claire Weinanfdd26902022-03-01 14:18:25 -0800329{
330 std::string entriesPath;
331
332 if (dumpType == "BMC")
333 {
334 entriesPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
335 }
336 else if (dumpType == "FaultLog")
337 {
338 entriesPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/";
339 }
340 else if (dumpType == "System")
341 {
342 entriesPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
343 }
344 else
345 {
346 BMCWEB_LOG_ERROR << "getDumpEntriesPath() invalid dump type: "
347 << dumpType;
348 }
349
350 // Returns empty string on error
351 return entriesPath;
352}
353
zhanghch058d1b46d2021-04-01 11:18:24 +0800354inline void
355 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
356 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500357{
Claire Weinanfdd26902022-03-01 14:18:25 -0800358 std::string entriesPath = getDumpEntriesPath(dumpType);
359 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500360 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500361 messages::internalError(asyncResp->res);
362 return;
363 }
364
365 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800366 [asyncResp, entriesPath,
Ed Tanous711ac7a2021-12-20 09:34:41 -0800367 dumpType](const boost::system::error_code ec,
368 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700369 if (ec)
370 {
371 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
372 messages::internalError(asyncResp->res);
373 return;
374 }
375
Claire Weinanfdd26902022-03-01 14:18:25 -0800376 // Remove ending slash
377 std::string odataIdStr = entriesPath;
378 if (!odataIdStr.empty())
379 {
380 odataIdStr.pop_back();
381 }
382
383 asyncResp->res.jsonValue["@odata.type"] =
384 "#LogEntryCollection.LogEntryCollection";
385 asyncResp->res.jsonValue["@odata.id"] = std::move(odataIdStr);
386 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entries";
387 asyncResp->res.jsonValue["Description"] =
388 "Collection of " + dumpType + " Dump Entries";
389
Ed Tanous002d39b2022-05-31 08:59:27 -0700390 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
391 entriesArray = nlohmann::json::array();
392 std::string dumpEntryPath =
393 "/xyz/openbmc_project/dump/" +
394 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
395
396 std::sort(resp.begin(), resp.end(), [](const auto& l, const auto& r) {
397 return AlphanumLess<std::string>()(l.first.filename(),
398 r.first.filename());
399 });
400
401 for (auto& object : resp)
402 {
403 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500404 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700405 continue;
406 }
407 uint64_t timestamp = 0;
408 uint64_t size = 0;
409 std::string dumpStatus;
410 nlohmann::json thisEntry;
411
412 std::string entryID = object.first.filename();
413 if (entryID.empty())
414 {
415 continue;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500416 }
417
Ed Tanous002d39b2022-05-31 08:59:27 -0700418 for (auto& interfaceMap : object.second)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500419 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700420 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500421 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700422 for (const auto& propertyMap : interfaceMap.second)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500423 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700424 if (propertyMap.first == "Status")
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500425 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700426 const auto* status =
427 std::get_if<std::string>(&propertyMap.second);
428 if (status == nullptr)
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500429 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700430 messages::internalError(asyncResp->res);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500431 break;
432 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700433 dumpStatus = *status;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500434 }
435 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 }
437 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
438 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500439
Ed Tanous002d39b2022-05-31 08:59:27 -0700440 for (auto& propertyMap : interfaceMap.second)
441 {
442 if (propertyMap.first == "Size")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500443 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700444 const auto* sizePtr =
445 std::get_if<uint64_t>(&propertyMap.second);
446 if (sizePtr == nullptr)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500447 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700448 messages::internalError(asyncResp->res);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500449 break;
450 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700451 size = *sizePtr;
452 break;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500453 }
454 }
455 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700456 else if (interfaceMap.first ==
457 "xyz.openbmc_project.Time.EpochTime")
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500458 {
Asmitha Karunanithi35440d12021-09-07 11:17:57 -0500459
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 for (const auto& propertyMap : interfaceMap.second)
461 {
462 if (propertyMap.first == "Elapsed")
463 {
464 const uint64_t* usecsTimeStamp =
465 std::get_if<uint64_t>(&propertyMap.second);
466 if (usecsTimeStamp == nullptr)
467 {
468 messages::internalError(asyncResp->res);
469 break;
470 }
471 timestamp = (*usecsTimeStamp / 1000 / 1000);
472 break;
473 }
474 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500475 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500476 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700477
478 if (dumpStatus !=
479 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
480 !dumpStatus.empty())
481 {
482 // Dump status is not Complete, no need to enumerate
483 continue;
484 }
485
486 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800487 thisEntry["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 thisEntry["Id"] = entryID;
489 thisEntry["EntryType"] = "Event";
490 thisEntry["Created"] = crow::utility::getDateTimeUint(timestamp);
491 thisEntry["Name"] = dumpType + " Dump Entry";
492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 if (dumpType == "BMC")
494 {
495 thisEntry["DiagnosticDataType"] = "Manager";
496 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800497 entriesPath + entryID + "/attachment";
498 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 }
500 else if (dumpType == "System")
501 {
502 thisEntry["DiagnosticDataType"] = "OEM";
503 thisEntry["OEMDiagnosticDataType"] = "System";
504 thisEntry["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800505 entriesPath + entryID + "/attachment";
506 thisEntry["AdditionalDataSizeBytes"] = size;
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 }
508 entriesArray.push_back(std::move(thisEntry));
509 }
510 asyncResp->res.jsonValue["Members@odata.count"] = entriesArray.size();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500511 },
512 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
513 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
514}
515
zhanghch058d1b46d2021-04-01 11:18:24 +0800516inline void
Claire Weinanc7a6d662022-06-13 16:36:39 -0700517 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
zhanghch058d1b46d2021-04-01 11:18:24 +0800518 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500519{
Claire Weinanfdd26902022-03-01 14:18:25 -0800520 std::string entriesPath = getDumpEntriesPath(dumpType);
521 if (entriesPath.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500522 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500523 messages::internalError(asyncResp->res);
524 return;
525 }
526
527 crow::connections::systemBus->async_method_call(
Claire Weinanfdd26902022-03-01 14:18:25 -0800528 [asyncResp, entryID, dumpType,
529 entriesPath](const boost::system::error_code ec,
530 dbus::utility::ManagedObjectType& resp) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700531 if (ec)
532 {
533 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
534 messages::internalError(asyncResp->res);
535 return;
536 }
537
538 bool foundDumpEntry = false;
539 std::string dumpEntryPath =
540 "/xyz/openbmc_project/dump/" +
541 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/";
542
543 for (const auto& objectPath : resp)
544 {
545 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500546 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700547 continue;
548 }
549
550 foundDumpEntry = true;
551 uint64_t timestamp = 0;
552 uint64_t size = 0;
553 std::string dumpStatus;
554
555 for (const auto& interfaceMap : objectPath.second)
556 {
557 if (interfaceMap.first == "xyz.openbmc_project.Common.Progress")
558 {
559 for (const auto& propertyMap : interfaceMap.second)
560 {
561 if (propertyMap.first == "Status")
562 {
563 const std::string* status =
564 std::get_if<std::string>(&propertyMap.second);
565 if (status == nullptr)
566 {
567 messages::internalError(asyncResp->res);
568 break;
569 }
570 dumpStatus = *status;
571 }
572 }
573 }
574 else if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
575 {
576 for (const auto& propertyMap : interfaceMap.second)
577 {
578 if (propertyMap.first == "Size")
579 {
580 const uint64_t* sizePtr =
581 std::get_if<uint64_t>(&propertyMap.second);
582 if (sizePtr == nullptr)
583 {
584 messages::internalError(asyncResp->res);
585 break;
586 }
587 size = *sizePtr;
588 break;
589 }
590 }
591 }
592 else if (interfaceMap.first ==
593 "xyz.openbmc_project.Time.EpochTime")
594 {
595 for (const auto& propertyMap : interfaceMap.second)
596 {
597 if (propertyMap.first == "Elapsed")
598 {
599 const uint64_t* usecsTimeStamp =
600 std::get_if<uint64_t>(&propertyMap.second);
601 if (usecsTimeStamp == nullptr)
602 {
603 messages::internalError(asyncResp->res);
604 break;
605 }
606 timestamp = *usecsTimeStamp / 1000 / 1000;
607 break;
608 }
609 }
610 }
611 }
612
613 if (dumpStatus !=
614 "xyz.openbmc_project.Common.Progress.OperationStatus.Completed" &&
615 !dumpStatus.empty())
616 {
617 // Dump status is not Complete
618 // return not found until status is changed to Completed
619 messages::resourceNotFound(asyncResp->res, dumpType + " dump",
620 entryID);
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500621 return;
622 }
623
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 asyncResp->res.jsonValue["@odata.type"] =
625 "#LogEntry.v1_8_0.LogEntry";
Claire Weinanfdd26902022-03-01 14:18:25 -0800626 asyncResp->res.jsonValue["@odata.id"] = entriesPath + entryID;
Ed Tanous002d39b2022-05-31 08:59:27 -0700627 asyncResp->res.jsonValue["Id"] = entryID;
628 asyncResp->res.jsonValue["EntryType"] = "Event";
629 asyncResp->res.jsonValue["Created"] =
630 crow::utility::getDateTimeUint(timestamp);
631 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500632
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 if (dumpType == "BMC")
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500634 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700635 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
636 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800637 entriesPath + entryID + "/attachment";
638 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 else if (dumpType == "System")
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500641 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700642 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
643 asyncResp->res.jsonValue["OEMDiagnosticDataType"] = "System";
644 asyncResp->res.jsonValue["AdditionalDataURI"] =
Claire Weinanfdd26902022-03-01 14:18:25 -0800645 entriesPath + entryID + "/attachment";
646 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500647 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700648 }
649 if (!foundDumpEntry)
650 {
651 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
652 messages::internalError(asyncResp->res);
653 return;
654 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500655 },
656 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
657 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
658}
659
zhanghch058d1b46d2021-04-01 11:18:24 +0800660inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800661 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500662 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500663{
Ed Tanous002d39b2022-05-31 08:59:27 -0700664 auto respHandler =
665 [asyncResp, entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500666 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
667 if (ec)
668 {
George Liu3de8d8b2021-03-22 17:49:39 +0800669 if (ec.value() == EBADR)
670 {
671 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
672 return;
673 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500674 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
Claire Weinanfdd26902022-03-01 14:18:25 -0800675 << ec << " entryID=" << entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500676 messages::internalError(asyncResp->res);
677 return;
678 }
679 };
680 crow::connections::systemBus->async_method_call(
681 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500682 "/xyz/openbmc_project/dump/" +
683 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
684 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500685 "xyz.openbmc_project.Object.Delete", "Delete");
686}
687
zhanghch058d1b46d2021-04-01 11:18:24 +0800688inline void
Ed Tanous98be3e32021-09-16 15:05:36 -0700689 createDumpTaskCallback(task::Payload&& payload,
zhanghch058d1b46d2021-04-01 11:18:24 +0800690 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
691 const uint32_t& dumpId, const std::string& dumpPath,
692 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500693{
694 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500695 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500696 boost::system::error_code err, sdbusplus::message::message& m,
697 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700698 if (err)
699 {
700 BMCWEB_LOG_ERROR << "Error in creating a dump";
701 taskData->state = "Cancelled";
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500702 return task::completed;
Ed Tanous002d39b2022-05-31 08:59:27 -0700703 }
704
705 dbus::utility::DBusInteracesMap interfacesList;
706
707 sdbusplus::message::object_path objPath;
708
709 m.read(objPath, interfacesList);
710
711 if (objPath.str ==
712 "/xyz/openbmc_project/dump/" +
713 std::string(boost::algorithm::to_lower_copy(dumpType)) +
714 "/entry/" + std::to_string(dumpId))
715 {
716 nlohmann::json retMessage = messages::success();
717 taskData->messages.emplace_back(retMessage);
718
719 std::string headerLoc =
720 "Location: " + dumpPath + std::to_string(dumpId);
721 taskData->payload->httpHeaders.emplace_back(std::move(headerLoc));
722
723 taskData->state = "Completed";
724 return task::completed;
725 }
726 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500727 },
Jason M. Bills4978b632022-02-22 14:17:43 -0800728 "type='signal',interface='org.freedesktop.DBus.ObjectManager',"
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500729 "member='InterfacesAdded', "
730 "path='/xyz/openbmc_project/dump'");
731
732 task->startTimer(std::chrono::minutes(3));
733 task->populateResp(asyncResp->res);
Ed Tanous98be3e32021-09-16 15:05:36 -0700734 task->payload.emplace(std::move(payload));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500735}
736
zhanghch058d1b46d2021-04-01 11:18:24 +0800737inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
738 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500739{
Claire Weinanfdd26902022-03-01 14:18:25 -0800740 std::string dumpPath = getDumpEntriesPath(dumpType);
741 if (dumpPath.empty())
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500742 {
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500743 messages::internalError(asyncResp->res);
744 return;
745 }
746
747 std::optional<std::string> diagnosticDataType;
748 std::optional<std::string> oemDiagnosticDataType;
749
Willy Tu15ed6782021-12-14 11:03:16 -0800750 if (!redfish::json_util::readJsonAction(
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500751 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
752 "OEMDiagnosticDataType", oemDiagnosticDataType))
753 {
754 return;
755 }
756
757 if (dumpType == "System")
758 {
759 if (!oemDiagnosticDataType || !diagnosticDataType)
760 {
Jason M. Bills4978b632022-02-22 14:17:43 -0800761 BMCWEB_LOG_ERROR
762 << "CreateDump action parameter 'DiagnosticDataType'/'OEMDiagnosticDataType' value not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500763 messages::actionParameterMissing(
764 asyncResp->res, "CollectDiagnosticData",
765 "DiagnosticDataType & OEMDiagnosticDataType");
766 return;
767 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700768 if ((*oemDiagnosticDataType != "System") ||
769 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500770 {
771 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
Ed Tanousace85d62021-10-26 12:45:59 -0700772 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500773 return;
774 }
775 }
776 else if (dumpType == "BMC")
777 {
778 if (!diagnosticDataType)
779 {
George Liu0fda0f12021-11-16 10:06:17 +0800780 BMCWEB_LOG_ERROR
781 << "CreateDump action parameter 'DiagnosticDataType' not found!";
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500782 messages::actionParameterMissing(
783 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
784 return;
785 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700786 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500787 {
788 BMCWEB_LOG_ERROR
789 << "Wrong parameter value passed for 'DiagnosticDataType'";
Ed Tanousace85d62021-10-26 12:45:59 -0700790 messages::internalError(asyncResp->res);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500791 return;
792 }
793 }
794
795 crow::connections::systemBus->async_method_call(
Ed Tanous98be3e32021-09-16 15:05:36 -0700796 [asyncResp, payload(task::Payload(req)), dumpPath,
797 dumpType](const boost::system::error_code ec,
798 const uint32_t& dumpId) mutable {
Ed Tanous002d39b2022-05-31 08:59:27 -0700799 if (ec)
800 {
801 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
802 messages::internalError(asyncResp->res);
803 return;
804 }
805 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500806
Ed Tanous002d39b2022-05-31 08:59:27 -0700807 createDumpTaskCallback(std::move(payload), asyncResp, dumpId, dumpPath,
808 dumpType);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500809 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500810 "xyz.openbmc_project.Dump.Manager",
811 "/xyz/openbmc_project/dump/" +
812 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500813 "xyz.openbmc_project.Dump.Create", "CreateDump");
814}
815
zhanghch058d1b46d2021-04-01 11:18:24 +0800816inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
817 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500818{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500819 std::string dumpTypeLowerCopy =
820 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800821
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500822 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800823 [asyncResp, dumpType](
824 const boost::system::error_code ec,
825 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700826 if (ec)
827 {
828 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
829 messages::internalError(asyncResp->res);
830 return;
831 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500832
Ed Tanous002d39b2022-05-31 08:59:27 -0700833 for (const std::string& path : subTreePaths)
834 {
835 sdbusplus::message::object_path objPath(path);
836 std::string logID = objPath.filename();
837 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500838 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700839 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500840 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700841 deleteDumpEntry(asyncResp, logID, dumpType);
842 }
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500843 },
844 "xyz.openbmc_project.ObjectMapper",
845 "/xyz/openbmc_project/object_mapper",
846 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500847 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
848 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
849 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500850}
851
Ed Tanousb9d36b42022-02-26 21:42:46 -0800852inline static void
853 parseCrashdumpParameters(const dbus::utility::DBusPropertiesMap& params,
854 std::string& filename, std::string& timestamp,
855 std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700856{
857 for (auto property : params)
858 {
859 if (property.first == "Timestamp")
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 timestamp = *value;
866 }
867 }
868 else if (property.first == "Filename")
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 filename = *value;
875 }
876 }
877 else if (property.first == "Log")
878 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500879 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500880 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700881 if (value != nullptr)
882 {
883 logfile = *value;
884 }
885 }
886 }
887}
888
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500889constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700890inline void requestRoutesSystemLogServiceCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -0700891{
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800892 /**
893 * Functions triggers appropriate requests on DBus
894 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700895 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/")
Ed Tanoused398212021-06-09 17:05:54 -0700896 .privileges(redfish::privileges::getLogServiceCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -0700897 .methods(boost::beast::http::verb::get)(
898 [&app](const crow::Request& req,
899 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000900 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700901 {
902 return;
903 }
904 // Collections don't include the static data added by SubRoute
905 // because it has a duplicate entry for members
906 asyncResp->res.jsonValue["@odata.type"] =
907 "#LogServiceCollection.LogServiceCollection";
908 asyncResp->res.jsonValue["@odata.id"] =
909 "/redfish/v1/Systems/system/LogServices";
910 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
911 asyncResp->res.jsonValue["Description"] =
912 "Collection of LogServices for this Computer System";
913 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
914 logServiceArray = nlohmann::json::array();
915 nlohmann::json::object_t eventLog;
916 eventLog["@odata.id"] =
917 "/redfish/v1/Systems/system/LogServices/EventLog";
918 logServiceArray.push_back(std::move(eventLog));
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500919#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700920 nlohmann::json::object_t dumpLog;
921 dumpLog["@odata.id"] = "/redfish/v1/Systems/system/LogServices/Dump";
922 logServiceArray.push_back(std::move(dumpLog));
raviteja-bc9bb6862020-02-03 11:53:32 -0600923#endif
924
Jason M. Billsd53dd412019-02-12 17:16:22 -0800925#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
Ed Tanous002d39b2022-05-31 08:59:27 -0700926 nlohmann::json::object_t crashdump;
927 crashdump["@odata.id"] =
928 "/redfish/v1/Systems/system/LogServices/Crashdump";
929 logServiceArray.push_back(std::move(crashdump));
Jason M. Billsd53dd412019-02-12 17:16:22 -0800930#endif
Spencer Kub7028eb2021-10-26 15:27:35 +0800931
932#ifdef BMCWEB_ENABLE_REDFISH_HOST_LOGGER
Ed Tanous002d39b2022-05-31 08:59:27 -0700933 nlohmann::json::object_t hostlogger;
934 hostlogger["@odata.id"] =
935 "/redfish/v1/Systems/system/LogServices/HostLogger";
936 logServiceArray.push_back(std::move(hostlogger));
Spencer Kub7028eb2021-10-26 15:27:35 +0800937#endif
Ed Tanous002d39b2022-05-31 08:59:27 -0700938 asyncResp->res.jsonValue["Members@odata.count"] =
939 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800940
Ed Tanous002d39b2022-05-31 08:59:27 -0700941 crow::connections::systemBus->async_method_call(
942 [asyncResp](const boost::system::error_code ec,
943 const dbus::utility::MapperGetSubTreePathsResponse&
944 subtreePath) {
945 if (ec)
946 {
947 BMCWEB_LOG_ERROR << ec;
948 return;
949 }
Ed Tanous45ca1b82022-03-25 13:07:27 -0700950
Ed Tanous002d39b2022-05-31 08:59:27 -0700951 for (const auto& pathStr : subtreePath)
952 {
953 if (pathStr.find("PostCode") != std::string::npos)
954 {
955 nlohmann::json& logServiceArrayLocal =
956 asyncResp->res.jsonValue["Members"];
957 logServiceArrayLocal.push_back(
958 {{"@odata.id",
959 "/redfish/v1/Systems/system/LogServices/PostCodes"}});
960 asyncResp->res.jsonValue["Members@odata.count"] =
961 logServiceArrayLocal.size();
962 return;
963 }
964 }
965 },
966 "xyz.openbmc_project.ObjectMapper",
967 "/xyz/openbmc_project/object_mapper",
968 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
969 std::array<const char*, 1>{postCodeIface});
Ed Tanous45ca1b82022-03-25 13:07:27 -0700970 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700971}
972
973inline void requestRoutesEventLogService(App& app)
974{
975 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Ed Tanoused398212021-06-09 17:05:54 -0700976 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -0700977 .methods(boost::beast::http::verb::get)(
978 [&app](const crow::Request& req,
979 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000980 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700981 {
982 return;
983 }
984 asyncResp->res.jsonValue["@odata.id"] =
985 "/redfish/v1/Systems/system/LogServices/EventLog";
986 asyncResp->res.jsonValue["@odata.type"] =
987 "#LogService.v1_1_0.LogService";
988 asyncResp->res.jsonValue["Name"] = "Event Log Service";
989 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
990 asyncResp->res.jsonValue["Id"] = "EventLog";
991 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +0530992
Ed Tanous002d39b2022-05-31 08:59:27 -0700993 std::pair<std::string, std::string> redfishDateTimeOffset =
994 crow::utility::getDateTimeOffsetNow();
Tejas Patil7c8c4052021-06-04 17:43:14 +0530995
Ed Tanous002d39b2022-05-31 08:59:27 -0700996 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
997 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
998 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +0530999
Ed Tanous002d39b2022-05-31 08:59:27 -07001000 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1001 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1002 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001003
Ed Tanous002d39b2022-05-31 08:59:27 -07001004 {"target",
1005 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog"}};
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001006 });
1007}
1008
1009inline void requestRoutesJournalEventLogClear(App& app)
1010{
Jason M. Bills4978b632022-02-22 14:17:43 -08001011 BMCWEB_ROUTE(
1012 app,
1013 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanous432a8902021-06-14 15:28:56 -07001014 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001015 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001016 [&app](const crow::Request& req,
1017 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001018 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001019 {
1020 return;
1021 }
1022 // Clear the EventLog by deleting the log files
1023 std::vector<std::filesystem::path> redfishLogFiles;
1024 if (getRedfishLogFiles(redfishLogFiles))
1025 {
1026 for (const std::filesystem::path& file : redfishLogFiles)
1027 {
1028 std::error_code ec;
1029 std::filesystem::remove(file, ec);
1030 }
1031 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001032
Ed Tanous002d39b2022-05-31 08:59:27 -07001033 // Reload rsyslog so it knows to start new log files
1034 crow::connections::systemBus->async_method_call(
1035 [asyncResp](const boost::system::error_code ec) {
1036 if (ec)
1037 {
1038 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1039 messages::internalError(asyncResp->res);
1040 return;
1041 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001042
Ed Tanous002d39b2022-05-31 08:59:27 -07001043 messages::success(asyncResp->res);
1044 },
1045 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1046 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1047 "replace");
1048 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001049}
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001050
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001051static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001052 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001053 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001054{
Jason M. Bills95820182019-04-22 16:25:34 -07001055 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001056 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001057 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001058 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001059 {
1060 return 1;
1061 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001062 std::string timestamp = logEntry.substr(0, space);
1063 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001064 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001065 if (entryStart == std::string::npos)
1066 {
1067 return 1;
1068 }
1069 std::string_view entry(logEntry);
1070 entry.remove_prefix(entryStart);
1071 // Use split to separate the entry into its fields
1072 std::vector<std::string> logEntryFields;
1073 boost::split(logEntryFields, entry, boost::is_any_of(","),
1074 boost::token_compress_on);
1075 // We need at least a MessageId to be valid
Ed Tanous26f69762022-01-25 09:49:11 -08001076 if (logEntryFields.empty())
Jason M. Billscd225da2019-05-08 15:31:57 -07001077 {
1078 return 1;
1079 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001080 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001081
Jason M. Bills4851d452019-03-28 11:27:48 -07001082 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08001083 const registries::Message* message = registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001084
Sui Chen54417b02022-03-24 14:59:52 -07001085 if (message == nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001086 {
Sui Chen54417b02022-03-24 14:59:52 -07001087 BMCWEB_LOG_WARNING << "Log entry not found in registry: " << logEntry;
1088 return 0;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001089 }
1090
Sui Chen54417b02022-03-24 14:59:52 -07001091 std::string msg = message->message;
1092
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001093 // Get the MessageArgs from the log if there are any
Ed Tanous26702d02021-11-03 15:02:33 -07001094 std::span<std::string> messageArgs;
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001095 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001096 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001097 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001098 // If the first string is empty, assume there are no MessageArgs
1099 std::size_t messageArgsSize = 0;
1100 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001101 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001102 messageArgsSize = logEntryFields.size() - 1;
1103 }
1104
Ed Tanous23a21a12020-07-25 04:45:05 +00001105 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001106
1107 // Fill the MessageArgs into the Message
1108 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001109 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001110 {
1111 std::string argStr = "%" + std::to_string(++i);
1112 size_t argPos = msg.find(argStr);
1113 if (argPos != std::string::npos)
1114 {
1115 msg.replace(argPos, argStr.length(), messageArg);
1116 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001117 }
1118 }
1119
Jason M. Bills95820182019-04-22 16:25:34 -07001120 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1121 // format which matches the Redfish format except for the fractional seconds
1122 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001123 std::size_t dot = timestamp.find_first_of('.');
1124 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001125 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001126 {
Jason M. Bills95820182019-04-22 16:25:34 -07001127 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001128 }
1129
1130 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001131 logEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08001132 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001133 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001134 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001135 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001136 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001137 {"Id", logEntryID},
1138 {"Message", std::move(msg)},
1139 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001140 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001141 {"EntryType", "Event"},
Sui Chen54417b02022-03-24 14:59:52 -07001142 {"Severity", message->messageSeverity},
Jason M. Bills95820182019-04-22 16:25:34 -07001143 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001144 return 0;
1145}
1146
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001147inline void requestRoutesJournalEventLogEntryCollection(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001148{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001149 BMCWEB_ROUTE(app,
1150 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Gunnar Mills8b6a35f2021-07-30 14:52:53 -05001151 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001152 .methods(boost::beast::http::verb::get)(
1153 [&app](const crow::Request& req,
1154 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1155 query_param::QueryCapabilities capabilities = {
1156 .canDelegateTop = true,
1157 .canDelegateSkip = true,
1158 };
1159 query_param::Query delegatedQuery;
1160 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001161 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001162 {
1163 return;
1164 }
1165 // Collections don't include the static data added by SubRoute
1166 // because it has a duplicate entry for members
1167 asyncResp->res.jsonValue["@odata.type"] =
1168 "#LogEntryCollection.LogEntryCollection";
1169 asyncResp->res.jsonValue["@odata.id"] =
1170 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1171 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1172 asyncResp->res.jsonValue["Description"] =
1173 "Collection of System Event Log Entries";
1174
1175 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1176 logEntryArray = nlohmann::json::array();
1177 // Go through the log files and create a unique ID for each
1178 // entry
1179 std::vector<std::filesystem::path> redfishLogFiles;
1180 getRedfishLogFiles(redfishLogFiles);
1181 uint64_t entryCount = 0;
1182 std::string logEntry;
1183
1184 // Oldest logs are in the last file, so start there and loop
1185 // backwards
1186 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1187 it++)
1188 {
1189 std::ifstream logStream(*it);
1190 if (!logStream.is_open())
Jason M. Bills4978b632022-02-22 14:17:43 -08001191 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001192 continue;
Jason M. Bills4978b632022-02-22 14:17:43 -08001193 }
Jason M. Bills897967d2019-07-29 17:05:30 -07001194
Ed Tanous002d39b2022-05-31 08:59:27 -07001195 // Reset the unique ID on the first entry
1196 bool firstEntry = true;
1197 while (std::getline(logStream, logEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001198 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001199 entryCount++;
1200 // Handle paging using skip (number of entries to skip
1201 // from the start) and top (number of entries to
1202 // display)
1203 if (entryCount <= delegatedQuery.skip ||
1204 entryCount > delegatedQuery.skip + delegatedQuery.top)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001205 {
Jason M. Bills4978b632022-02-22 14:17:43 -08001206 continue;
1207 }
1208
Ed Tanous002d39b2022-05-31 08:59:27 -07001209 std::string idStr;
1210 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills4978b632022-02-22 14:17:43 -08001211 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001212 continue;
1213 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001214 firstEntry = false;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001215
Ed Tanous002d39b2022-05-31 08:59:27 -07001216 logEntryArray.push_back({});
1217 nlohmann::json& bmcLogEntry = logEntryArray.back();
1218 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1219 {
1220 messages::internalError(asyncResp->res);
1221 return;
Andrew Geisslercb92c032018-08-17 07:56:14 -07001222 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001223 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001224 }
1225 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1226 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
1227 {
1228 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1229 "/redfish/v1/Systems/system/LogServices/EventLog/Entries?$skip=" +
1230 std::to_string(delegatedQuery.skip + delegatedQuery.top);
1231 }
Jason M. Bills4978b632022-02-22 14:17:43 -08001232 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001233}
Chicago Duan336e96c2019-07-15 14:22:08 +08001234
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001235inline void requestRoutesJournalEventLogEntry(App& app)
1236{
1237 BMCWEB_ROUTE(
1238 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001239 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001240 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001241 [&app](const crow::Request& req,
1242 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1243 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001244 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001245 {
1246 return;
1247 }
1248 const std::string& targetID = param;
1249
1250 // Go through the log files and check the unique ID for each
1251 // entry to find the target entry
1252 std::vector<std::filesystem::path> redfishLogFiles;
1253 getRedfishLogFiles(redfishLogFiles);
1254 std::string logEntry;
1255
1256 // Oldest logs are in the last file, so start there and loop
1257 // backwards
1258 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1259 it++)
1260 {
1261 std::ifstream logStream(*it);
1262 if (!logStream.is_open())
1263 {
1264 continue;
1265 }
1266
1267 // Reset the unique ID on the first entry
1268 bool firstEntry = true;
1269 while (std::getline(logStream, logEntry))
1270 {
1271 std::string idStr;
1272 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Ed Tanous45ca1b82022-03-25 13:07:27 -07001273 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001274 continue;
1275 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07001276 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07001277
1278 if (idStr == targetID)
1279 {
1280 if (fillEventLogEntryJson(idStr, logEntry,
1281 asyncResp->res.jsonValue) != 0)
1282 {
1283 messages::internalError(asyncResp->res);
1284 return;
1285 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07001286 return;
1287 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001288 }
1289 }
1290 // Requested ID was not found
1291 messages::resourceMissingAtURI(asyncResp->res,
1292 crow::utility::urlFromPieces(targetID));
1293 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001294}
1295
1296inline void requestRoutesDBusEventLogEntryCollection(App& app)
1297{
1298 BMCWEB_ROUTE(app,
1299 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07001300 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07001301 .methods(boost::beast::http::verb::get)(
1302 [&app](const crow::Request& req,
1303 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001304 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001305 {
1306 return;
1307 }
1308 // Collections don't include the static data added by SubRoute
1309 // because it has a duplicate entry for members
1310 asyncResp->res.jsonValue["@odata.type"] =
1311 "#LogEntryCollection.LogEntryCollection";
1312 asyncResp->res.jsonValue["@odata.id"] =
1313 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1314 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1315 asyncResp->res.jsonValue["Description"] =
1316 "Collection of System Event Log Entries";
1317
1318 // DBus implementation of EventLog/Entries
1319 // Make call to Logging Service to find all log entry objects
1320 crow::connections::systemBus->async_method_call(
1321 [asyncResp](const boost::system::error_code ec,
1322 const dbus::utility::ManagedObjectType& resp) {
1323 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001324 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001325 // TODO Handle for specific error code
1326 BMCWEB_LOG_ERROR
1327 << "getLogEntriesIfaceData resp_handler got error " << ec;
1328 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001329 return;
1330 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001331 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
1332 entriesArray = nlohmann::json::array();
1333 for (const auto& objectPath : resp)
1334 {
1335 const uint32_t* id = nullptr;
1336 const uint64_t* timestamp = nullptr;
1337 const uint64_t* updateTimestamp = nullptr;
1338 const std::string* severity = nullptr;
1339 const std::string* message = nullptr;
1340 const std::string* filePath = nullptr;
1341 bool resolved = false;
1342 for (const auto& interfaceMap : objectPath.second)
1343 {
1344 if (interfaceMap.first ==
1345 "xyz.openbmc_project.Logging.Entry")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001346 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001347 for (const auto& propertyMap : interfaceMap.second)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001348 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001349 if (propertyMap.first == "Id")
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001350 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001351 id = std::get_if<uint32_t>(&propertyMap.second);
1352 }
1353 else if (propertyMap.first == "Timestamp")
1354 {
1355 timestamp =
1356 std::get_if<uint64_t>(&propertyMap.second);
1357 }
1358 else if (propertyMap.first == "UpdateTimestamp")
1359 {
1360 updateTimestamp =
1361 std::get_if<uint64_t>(&propertyMap.second);
1362 }
1363 else if (propertyMap.first == "Severity")
1364 {
1365 severity = std::get_if<std::string>(
1366 &propertyMap.second);
1367 }
1368 else if (propertyMap.first == "Message")
1369 {
1370 message = std::get_if<std::string>(
1371 &propertyMap.second);
1372 }
1373 else if (propertyMap.first == "Resolved")
1374 {
1375 const bool* resolveptr =
1376 std::get_if<bool>(&propertyMap.second);
1377 if (resolveptr == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001378 {
1379 messages::internalError(asyncResp->res);
1380 return;
1381 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001382 resolved = *resolveptr;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001383 }
1384 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001385 if (id == nullptr || message == nullptr ||
Ed Tanous002d39b2022-05-31 08:59:27 -07001386 severity == nullptr)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001387 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001388 messages::internalError(asyncResp->res);
1389 return;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001390 }
1391 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001392 else if (interfaceMap.first ==
1393 "xyz.openbmc_project.Common.FilePath")
1394 {
1395 for (const auto& propertyMap : interfaceMap.second)
1396 {
1397 if (propertyMap.first == "Path")
1398 {
1399 filePath = std::get_if<std::string>(
1400 &propertyMap.second);
1401 }
1402 }
1403 }
1404 }
1405 // Object path without the
1406 // xyz.openbmc_project.Logging.Entry interface, ignore
1407 // and continue.
1408 if (id == nullptr || message == nullptr ||
1409 severity == nullptr || timestamp == nullptr ||
1410 updateTimestamp == nullptr)
1411 {
1412 continue;
1413 }
1414 entriesArray.push_back({});
1415 nlohmann::json& thisEntry = entriesArray.back();
1416 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1417 thisEntry["@odata.id"] =
1418 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1419 std::to_string(*id);
1420 thisEntry["Name"] = "System Event Log Entry";
1421 thisEntry["Id"] = std::to_string(*id);
1422 thisEntry["Message"] = *message;
1423 thisEntry["Resolved"] = resolved;
1424 thisEntry["EntryType"] = "Event";
1425 thisEntry["Severity"] =
1426 translateSeverityDbusToRedfish(*severity);
1427 thisEntry["Created"] =
1428 crow::utility::getDateTimeUintMs(*timestamp);
1429 thisEntry["Modified"] =
1430 crow::utility::getDateTimeUintMs(*updateTimestamp);
1431 if (filePath != nullptr)
1432 {
1433 thisEntry["AdditionalDataURI"] =
1434 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1435 std::to_string(*id) + "/attachment";
1436 }
1437 }
1438 std::sort(
1439 entriesArray.begin(), entriesArray.end(),
1440 [](const nlohmann::json& left, const nlohmann::json& right) {
1441 return (left["Id"] <= right["Id"]);
1442 });
1443 asyncResp->res.jsonValue["Members@odata.count"] =
1444 entriesArray.size();
1445 },
1446 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1447 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001448 });
1449}
Xiaochao Ma75710de2021-01-21 17:56:02 +08001450
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001451inline void requestRoutesDBusEventLogEntry(App& app)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001452{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001453 BMCWEB_ROUTE(
1454 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001455 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001456 .methods(boost::beast::http::verb::get)(
1457 [&app](const crow::Request& req,
1458 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1459 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001460 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001461 {
1462 return;
1463 }
1464 std::string entryID = param;
1465 dbus::utility::escapePathForDbus(entryID);
1466
1467 // DBus implementation of EventLog/Entries
1468 // Make call to Logging Service to find all log entry objects
1469 crow::connections::systemBus->async_method_call(
1470 [asyncResp, entryID](const boost::system::error_code ec,
1471 const dbus::utility::DBusPropertiesMap& resp) {
1472 if (ec.value() == EBADR)
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001473 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001474 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1475 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001476 return;
1477 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001478 if (ec)
1479 {
1480 BMCWEB_LOG_ERROR
1481 << "EventLogEntry (DBus) resp_handler got error " << ec;
1482 messages::internalError(asyncResp->res);
1483 return;
1484 }
1485 const uint32_t* id = nullptr;
1486 const uint64_t* timestamp = nullptr;
1487 const uint64_t* updateTimestamp = nullptr;
1488 const std::string* severity = nullptr;
1489 const std::string* message = nullptr;
1490 const std::string* filePath = nullptr;
1491 bool resolved = false;
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001492
Ed Tanous002d39b2022-05-31 08:59:27 -07001493 for (const auto& propertyMap : resp)
1494 {
1495 if (propertyMap.first == "Id")
1496 {
1497 id = std::get_if<uint32_t>(&propertyMap.second);
1498 }
1499 else if (propertyMap.first == "Timestamp")
1500 {
1501 timestamp = std::get_if<uint64_t>(&propertyMap.second);
1502 }
1503 else if (propertyMap.first == "UpdateTimestamp")
1504 {
1505 updateTimestamp =
1506 std::get_if<uint64_t>(&propertyMap.second);
1507 }
1508 else if (propertyMap.first == "Severity")
1509 {
1510 severity = std::get_if<std::string>(&propertyMap.second);
1511 }
1512 else if (propertyMap.first == "Message")
1513 {
1514 message = std::get_if<std::string>(&propertyMap.second);
1515 }
1516 else if (propertyMap.first == "Resolved")
1517 {
1518 const bool* resolveptr =
1519 std::get_if<bool>(&propertyMap.second);
1520 if (resolveptr == nullptr)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001521 {
1522 messages::internalError(asyncResp->res);
1523 return;
1524 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001525 resolved = *resolveptr;
1526 }
1527 else if (propertyMap.first == "Path")
1528 {
1529 filePath = std::get_if<std::string>(&propertyMap.second);
1530 }
1531 }
1532 if (id == nullptr || message == nullptr || severity == nullptr ||
1533 timestamp == nullptr || updateTimestamp == nullptr)
1534 {
1535 messages::internalError(asyncResp->res);
1536 return;
1537 }
1538 asyncResp->res.jsonValue["@odata.type"] =
1539 "#LogEntry.v1_8_0.LogEntry";
1540 asyncResp->res.jsonValue["@odata.id"] =
1541 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1542 std::to_string(*id);
1543 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1544 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1545 asyncResp->res.jsonValue["Message"] = *message;
1546 asyncResp->res.jsonValue["Resolved"] = resolved;
1547 asyncResp->res.jsonValue["EntryType"] = "Event";
1548 asyncResp->res.jsonValue["Severity"] =
1549 translateSeverityDbusToRedfish(*severity);
1550 asyncResp->res.jsonValue["Created"] =
1551 crow::utility::getDateTimeUintMs(*timestamp);
1552 asyncResp->res.jsonValue["Modified"] =
1553 crow::utility::getDateTimeUintMs(*updateTimestamp);
1554 if (filePath != nullptr)
1555 {
1556 asyncResp->res.jsonValue["AdditionalDataURI"] =
1557 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1558 std::to_string(*id) + "/attachment";
1559 }
1560 },
1561 "xyz.openbmc_project.Logging",
1562 "/xyz/openbmc_project/logging/entry/" + entryID,
1563 "org.freedesktop.DBus.Properties", "GetAll", "");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001564 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001565
1566 BMCWEB_ROUTE(
1567 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001568 .privileges(redfish::privileges::patchLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001569 .methods(boost::beast::http::verb::patch)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001570 [&app](const crow::Request& req,
1571 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1572 const std::string& entryId) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001573 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001574 {
1575 return;
1576 }
1577 std::optional<bool> resolved;
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001578
Ed Tanous002d39b2022-05-31 08:59:27 -07001579 if (!json_util::readJsonPatch(req, asyncResp->res, "Resolved",
1580 resolved))
1581 {
1582 return;
1583 }
1584 BMCWEB_LOG_DEBUG << "Set Resolved";
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001585
Ed Tanous002d39b2022-05-31 08:59:27 -07001586 crow::connections::systemBus->async_method_call(
1587 [asyncResp, entryId](const boost::system::error_code ec) {
1588 if (ec)
1589 {
1590 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1591 messages::internalError(asyncResp->res);
1592 return;
1593 }
1594 },
1595 "xyz.openbmc_project.Logging",
1596 "/xyz/openbmc_project/logging/entry/" + entryId,
1597 "org.freedesktop.DBus.Properties", "Set",
1598 "xyz.openbmc_project.Logging.Entry", "Resolved",
1599 dbus::utility::DbusVariantType(*resolved));
1600 });
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001601
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001602 BMCWEB_ROUTE(
1603 app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07001604 .privileges(redfish::privileges::deleteLogEntry)
1605
Ed Tanous002d39b2022-05-31 08:59:27 -07001606 .methods(boost::beast::http::verb::delete_)(
1607 [&app](const crow::Request& req,
1608 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1609 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001610 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001611 {
1612 return;
1613 }
1614 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1615
1616 std::string entryID = param;
1617
1618 dbus::utility::escapePathForDbus(entryID);
1619
1620 // Process response from Logging service.
1621 auto respHandler =
1622 [asyncResp, entryID](const boost::system::error_code ec) {
1623 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1624 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001625 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001626 if (ec.value() == EBADR)
Ed Tanous45ca1b82022-03-25 13:07:27 -07001627 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001628 messages::resourceNotFound(asyncResp->res, "LogEntry",
1629 entryID);
Ed Tanous45ca1b82022-03-25 13:07:27 -07001630 return;
1631 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001632 // TODO Handle for specific error code
1633 BMCWEB_LOG_ERROR
1634 << "EventLogEntry (DBus) doDelete respHandler got error "
1635 << ec;
1636 asyncResp->res.result(
1637 boost::beast::http::status::internal_server_error);
1638 return;
1639 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001640
Ed Tanous002d39b2022-05-31 08:59:27 -07001641 asyncResp->res.result(boost::beast::http::status::ok);
1642 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001643
Ed Tanous002d39b2022-05-31 08:59:27 -07001644 // Make call to Logging service to request Delete Log
1645 crow::connections::systemBus->async_method_call(
1646 respHandler, "xyz.openbmc_project.Logging",
1647 "/xyz/openbmc_project/logging/entry/" + entryID,
1648 "xyz.openbmc_project.Object.Delete", "Delete");
Ed Tanous45ca1b82022-03-25 13:07:27 -07001649 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001650}
1651
1652inline void requestRoutesDBusEventLogEntryDownload(App& app)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001653{
George Liu0fda0f12021-11-16 10:06:17 +08001654 BMCWEB_ROUTE(
1655 app,
1656 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/attachment")
Ed Tanoused398212021-06-09 17:05:54 -07001657 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001658 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001659 [&app](const crow::Request& req,
1660 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1661 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001662 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001663 {
1664 return;
1665 }
1666 if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
1667 {
1668 asyncResp->res.result(boost::beast::http::status::bad_request);
1669 return;
1670 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001671
Ed Tanous002d39b2022-05-31 08:59:27 -07001672 std::string entryID = param;
1673 dbus::utility::escapePathForDbus(entryID);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001674
Ed Tanous002d39b2022-05-31 08:59:27 -07001675 crow::connections::systemBus->async_method_call(
1676 [asyncResp, entryID](const boost::system::error_code ec,
1677 const sdbusplus::message::unix_fd& unixfd) {
1678 if (ec.value() == EBADR)
1679 {
1680 messages::resourceNotFound(asyncResp->res, "EventLogAttachment",
1681 entryID);
1682 return;
1683 }
1684 if (ec)
1685 {
1686 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1687 messages::internalError(asyncResp->res);
1688 return;
1689 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001690
Ed Tanous002d39b2022-05-31 08:59:27 -07001691 int fd = -1;
1692 fd = dup(unixfd);
1693 if (fd == -1)
1694 {
1695 messages::internalError(asyncResp->res);
1696 return;
1697 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001698
Ed Tanous002d39b2022-05-31 08:59:27 -07001699 long long int size = lseek(fd, 0, SEEK_END);
1700 if (size == -1)
1701 {
1702 messages::internalError(asyncResp->res);
1703 return;
1704 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001705
Ed Tanous002d39b2022-05-31 08:59:27 -07001706 // Arbitrary max size of 64kb
1707 constexpr int maxFileSize = 65536;
1708 if (size > maxFileSize)
1709 {
1710 BMCWEB_LOG_ERROR << "File size exceeds maximum allowed size of "
1711 << maxFileSize;
1712 messages::internalError(asyncResp->res);
1713 return;
1714 }
1715 std::vector<char> data(static_cast<size_t>(size));
1716 long long int rc = lseek(fd, 0, SEEK_SET);
1717 if (rc == -1)
1718 {
1719 messages::internalError(asyncResp->res);
1720 return;
1721 }
1722 rc = read(fd, data.data(), data.size());
1723 if ((rc == -1) || (rc != size))
1724 {
1725 messages::internalError(asyncResp->res);
1726 return;
1727 }
1728 close(fd);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001729
Ed Tanous002d39b2022-05-31 08:59:27 -07001730 std::string_view strData(data.data(), data.size());
1731 std::string output = crow::utility::base64encode(strData);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001732
Ed Tanous002d39b2022-05-31 08:59:27 -07001733 asyncResp->res.addHeader("Content-Type",
1734 "application/octet-stream");
1735 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1736 asyncResp->res.body() = std::move(output);
1737 },
1738 "xyz.openbmc_project.Logging",
1739 "/xyz/openbmc_project/logging/entry/" + entryID,
1740 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1741 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07001742}
1743
Spencer Kub7028eb2021-10-26 15:27:35 +08001744constexpr const char* hostLoggerFolderPath = "/var/log/console";
1745
1746inline bool
1747 getHostLoggerFiles(const std::string& hostLoggerFilePath,
1748 std::vector<std::filesystem::path>& hostLoggerFiles)
1749{
1750 std::error_code ec;
1751 std::filesystem::directory_iterator logPath(hostLoggerFilePath, ec);
1752 if (ec)
1753 {
1754 BMCWEB_LOG_ERROR << ec.message();
1755 return false;
1756 }
1757 for (const std::filesystem::directory_entry& it : logPath)
1758 {
1759 std::string filename = it.path().filename();
1760 // Prefix of each log files is "log". Find the file and save the
1761 // path
1762 if (boost::starts_with(filename, "log"))
1763 {
1764 hostLoggerFiles.emplace_back(it.path());
1765 }
1766 }
1767 // As the log files rotate, they are appended with a ".#" that is higher for
1768 // the older logs. Since we start from oldest logs, sort the name in
1769 // descending order.
1770 std::sort(hostLoggerFiles.rbegin(), hostLoggerFiles.rend(),
1771 AlphanumLess<std::string>());
1772
1773 return true;
1774}
1775
1776inline bool
1777 getHostLoggerEntries(std::vector<std::filesystem::path>& hostLoggerFiles,
Ed Tanousc937d2b2022-04-05 09:58:00 -07001778 uint64_t skip, uint64_t top,
Spencer Kub7028eb2021-10-26 15:27:35 +08001779 std::vector<std::string>& logEntries, size_t& logCount)
1780{
1781 GzFileReader logFile;
1782
1783 // Go though all log files and expose host logs.
1784 for (const std::filesystem::path& it : hostLoggerFiles)
1785 {
1786 if (!logFile.gzGetLines(it.string(), skip, top, logEntries, logCount))
1787 {
1788 BMCWEB_LOG_ERROR << "fail to expose host logs";
1789 return false;
1790 }
1791 }
1792 // Get lastMessage from constructor by getter
1793 std::string lastMessage = logFile.getLastMessage();
1794 if (!lastMessage.empty())
1795 {
1796 logCount++;
1797 if (logCount > skip && logCount <= (skip + top))
1798 {
1799 logEntries.push_back(lastMessage);
1800 }
1801 }
1802 return true;
1803}
1804
1805inline void fillHostLoggerEntryJson(const std::string& logEntryID,
1806 const std::string& msg,
1807 nlohmann::json& logEntryJson)
1808{
1809 // Fill in the log entry with the gathered data.
1810 logEntryJson = {
1811 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
1812 {"@odata.id",
1813 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/" +
1814 logEntryID},
1815 {"Name", "Host Logger Entry"},
1816 {"Id", logEntryID},
1817 {"Message", msg},
1818 {"EntryType", "Oem"},
1819 {"Severity", "OK"},
1820 {"OemRecordFormat", "Host Logger Entry"}};
1821}
1822
1823inline void requestRoutesSystemHostLogger(App& app)
1824{
1825 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/HostLogger/")
1826 .privileges(redfish::privileges::getLogService)
Ed Tanous14766872022-03-15 10:44:42 -07001827 .methods(boost::beast::http::verb::get)(
1828 [&app](const crow::Request& req,
1829 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001830 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001831 {
1832 return;
1833 }
1834 asyncResp->res.jsonValue["@odata.id"] =
1835 "/redfish/v1/Systems/system/LogServices/HostLogger";
1836 asyncResp->res.jsonValue["@odata.type"] =
1837 "#LogService.v1_1_0.LogService";
1838 asyncResp->res.jsonValue["Name"] = "Host Logger Service";
1839 asyncResp->res.jsonValue["Description"] = "Host Logger Service";
1840 asyncResp->res.jsonValue["Id"] = "HostLogger";
1841 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
1842 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1843 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001844}
1845
1846inline void requestRoutesSystemHostLoggerCollection(App& app)
1847{
1848 BMCWEB_ROUTE(app,
1849 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/")
1850 .privileges(redfish::privileges::getLogEntry)
Ed Tanous002d39b2022-05-31 08:59:27 -07001851 .methods(boost::beast::http::verb::get)(
1852 [&app](const crow::Request& req,
1853 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1854 query_param::QueryCapabilities capabilities = {
1855 .canDelegateTop = true,
1856 .canDelegateSkip = true,
1857 };
1858 query_param::Query delegatedQuery;
1859 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00001860 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07001861 {
1862 return;
1863 }
1864 asyncResp->res.jsonValue["@odata.id"] =
1865 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries";
1866 asyncResp->res.jsonValue["@odata.type"] =
1867 "#LogEntryCollection.LogEntryCollection";
1868 asyncResp->res.jsonValue["Name"] = "HostLogger Entries";
1869 asyncResp->res.jsonValue["Description"] =
1870 "Collection of HostLogger Entries";
1871 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
1872 logEntryArray = nlohmann::json::array();
1873 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Spencer Kub7028eb2021-10-26 15:27:35 +08001874
Ed Tanous002d39b2022-05-31 08:59:27 -07001875 std::vector<std::filesystem::path> hostLoggerFiles;
1876 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1877 {
1878 BMCWEB_LOG_ERROR << "fail to get host log file path";
1879 return;
1880 }
1881
1882 size_t logCount = 0;
1883 // This vector only store the entries we want to expose that
1884 // control by skip and top.
1885 std::vector<std::string> logEntries;
1886 if (!getHostLoggerEntries(hostLoggerFiles, delegatedQuery.skip,
1887 delegatedQuery.top, logEntries, logCount))
1888 {
1889 messages::internalError(asyncResp->res);
1890 return;
1891 }
1892 // If vector is empty, that means skip value larger than total
1893 // log count
1894 if (logEntries.empty())
1895 {
1896 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1897 return;
1898 }
1899 if (!logEntries.empty())
1900 {
1901 for (size_t i = 0; i < logEntries.size(); i++)
George Liu0fda0f12021-11-16 10:06:17 +08001902 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001903 logEntryArray.push_back({});
1904 nlohmann::json& hostLogEntry = logEntryArray.back();
1905 fillHostLoggerEntryJson(std::to_string(delegatedQuery.skip + i),
1906 logEntries[i], hostLogEntry);
George Liu0fda0f12021-11-16 10:06:17 +08001907 }
1908
Ed Tanous002d39b2022-05-31 08:59:27 -07001909 asyncResp->res.jsonValue["Members@odata.count"] = logCount;
1910 if (delegatedQuery.skip + delegatedQuery.top < logCount)
George Liu0fda0f12021-11-16 10:06:17 +08001911 {
Ed Tanous002d39b2022-05-31 08:59:27 -07001912 asyncResp->res.jsonValue["Members@odata.nextLink"] =
1913 "/redfish/v1/Systems/system/LogServices/HostLogger/Entries?$skip=" +
1914 std::to_string(delegatedQuery.skip + delegatedQuery.top);
George Liu0fda0f12021-11-16 10:06:17 +08001915 }
Ed Tanous002d39b2022-05-31 08:59:27 -07001916 }
George Liu0fda0f12021-11-16 10:06:17 +08001917 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001918}
1919
1920inline void requestRoutesSystemHostLoggerLogEntry(App& app)
1921{
1922 BMCWEB_ROUTE(
1923 app, "/redfish/v1/Systems/system/LogServices/HostLogger/Entries/<str>/")
1924 .privileges(redfish::privileges::getLogEntry)
1925 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07001926 [&app](const crow::Request& req,
1927 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1928 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00001929 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07001930 {
1931 return;
1932 }
1933 const std::string& targetID = param;
Spencer Kub7028eb2021-10-26 15:27:35 +08001934
Ed Tanous002d39b2022-05-31 08:59:27 -07001935 uint64_t idInt = 0;
Ed Tanousca45aa32022-01-07 09:28:45 -08001936
Ed Tanous002d39b2022-05-31 08:59:27 -07001937 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
1938 const char* end = targetID.data() + targetID.size();
Ed Tanousca45aa32022-01-07 09:28:45 -08001939
Ed Tanous002d39b2022-05-31 08:59:27 -07001940 auto [ptr, ec] = std::from_chars(targetID.data(), end, idInt);
1941 if (ec == std::errc::invalid_argument)
1942 {
1943 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1944 return;
1945 }
1946 if (ec == std::errc::result_out_of_range)
1947 {
1948 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1949 return;
1950 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001951
Ed Tanous002d39b2022-05-31 08:59:27 -07001952 std::vector<std::filesystem::path> hostLoggerFiles;
1953 if (!getHostLoggerFiles(hostLoggerFolderPath, hostLoggerFiles))
1954 {
1955 BMCWEB_LOG_ERROR << "fail to get host log file path";
1956 return;
1957 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001958
Ed Tanous002d39b2022-05-31 08:59:27 -07001959 size_t logCount = 0;
1960 uint64_t top = 1;
1961 std::vector<std::string> logEntries;
1962 // We can get specific entry by skip and top. For example, if we
1963 // want to get nth entry, we can set skip = n-1 and top = 1 to
1964 // get that entry
1965 if (!getHostLoggerEntries(hostLoggerFiles, idInt, top, logEntries,
1966 logCount))
1967 {
1968 messages::internalError(asyncResp->res);
1969 return;
1970 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001971
Ed Tanous002d39b2022-05-31 08:59:27 -07001972 if (!logEntries.empty())
1973 {
1974 fillHostLoggerEntryJson(targetID, logEntries[0],
1975 asyncResp->res.jsonValue);
1976 return;
1977 }
Spencer Kub7028eb2021-10-26 15:27:35 +08001978
Ed Tanous002d39b2022-05-31 08:59:27 -07001979 // Requested ID was not found
1980 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
1981 });
Spencer Kub7028eb2021-10-26 15:27:35 +08001982}
1983
Claire Weinanfdd26902022-03-01 14:18:25 -08001984constexpr char const* dumpManagerIface =
1985 "xyz.openbmc_project.Collection.DeleteAll";
1986inline void handleLogServicesCollectionGet(
1987 crow::App& app, const crow::Request& req,
1988 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1989{
1990 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1991 {
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();
2005
2006#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
2007 logServiceArray.push_back(
2008 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
2009#endif
2010
2011 asyncResp->res.jsonValue["Members@odata.count"] = logServiceArray.size();
2012
2013#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
2014 auto respHandler =
2015 [asyncResp](
2016 const boost::system::error_code ec,
2017 const dbus::utility::MapperGetSubTreePathsResponse& subTreePaths) {
2018 if (ec)
2019 {
2020 BMCWEB_LOG_ERROR
2021 << "handleLogServicesCollectionGet respHandler got error "
2022 << ec;
2023 // Assume that getting an error simply means there are no dump
2024 // LogServices. Return without adding any error response.
2025 return;
2026 }
2027
2028 nlohmann::json& logServiceArrayLocal =
2029 asyncResp->res.jsonValue["Members"];
2030
2031 for (const std::string& path : subTreePaths)
2032 {
2033 if (path == "/xyz/openbmc_project/dump/bmc")
2034 {
2035 logServiceArrayLocal.push_back(
2036 {{"@odata.id",
2037 "/redfish/v1/Managers/bmc/LogServices/Dump"}});
2038 }
2039 else if (path == "/xyz/openbmc_project/dump/faultlog")
2040 {
2041 logServiceArrayLocal.push_back(
2042 {{"@odata.id",
2043 "/redfish/v1/Managers/bmc/LogServices/FaultLog"}});
2044 }
2045 }
2046
2047 asyncResp->res.jsonValue["Members@odata.count"] =
2048 logServiceArrayLocal.size();
2049 };
2050
2051 crow::connections::systemBus->async_method_call(
2052 respHandler, "xyz.openbmc_project.ObjectMapper",
2053 "/xyz/openbmc_project/object_mapper",
2054 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
2055 "/xyz/openbmc_project/dump", 0,
2056 std::array<const char*, 1>{dumpManagerIface});
2057#endif
2058}
2059
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002060inline void requestRoutesBMCLogServiceCollection(App& app)
2061{
2062 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/")
Gunnar Millsad89dcf2021-07-30 14:40:11 -05002063 .privileges(redfish::privileges::getLogServiceCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002064 .methods(boost::beast::http::verb::get)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002065 std::bind_front(handleLogServicesCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002066}
Ed Tanous1da66f72018-07-27 16:13:37 -07002067
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002068inline void requestRoutesBMCJournalLogService(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002069{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002070 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Ed Tanoused398212021-06-09 17:05:54 -07002071 .privileges(redfish::privileges::getLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002072 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002073 [&app](const crow::Request& req,
2074 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002075 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002076 {
2077 return;
2078 }
2079 asyncResp->res.jsonValue["@odata.type"] =
2080 "#LogService.v1_1_0.LogService";
2081 asyncResp->res.jsonValue["@odata.id"] =
2082 "/redfish/v1/Managers/bmc/LogServices/Journal";
2083 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
2084 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
2085 asyncResp->res.jsonValue["Id"] = "BMC Journal";
2086 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302087
Ed Tanous002d39b2022-05-31 08:59:27 -07002088 std::pair<std::string, std::string> redfishDateTimeOffset =
2089 crow::utility::getDateTimeOffsetNow();
2090 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2091 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2092 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302093
Ed Tanous002d39b2022-05-31 08:59:27 -07002094 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2095 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2096 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002097}
Jason M. Billse1f26342018-07-18 12:12:00 -07002098
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002099static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
2100 sd_journal* journal,
2101 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07002102{
2103 // Get the Log Entry contents
2104 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07002105
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002106 std::string message;
2107 std::string_view syslogID;
2108 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
2109 if (ret < 0)
2110 {
2111 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
2112 << strerror(-ret);
2113 }
2114 if (!syslogID.empty())
2115 {
2116 message += std::string(syslogID) + ": ";
2117 }
2118
Ed Tanous39e77502019-03-04 17:35:53 -08002119 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07002120 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002121 if (ret < 0)
2122 {
2123 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
2124 return 1;
2125 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002126 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07002127
2128 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07002129 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07002130 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07002131 if (ret < 0)
2132 {
2133 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002134 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002135
2136 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002137 std::string entryTimeStr;
2138 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002139 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002140 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002141 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002142
2143 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002144 bmcJournalLogEntryJson = {
George Liu647b3cd2021-07-05 12:43:56 +08002145 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002146 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2147 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002148 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002149 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002150 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002151 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002152 {"Severity", severity <= 2 ? "Critical"
2153 : severity <= 4 ? "Warning"
2154 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002155 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002156 {"Created", std::move(entryTimeStr)}};
2157 return 0;
2158}
2159
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002160inline void requestRoutesBMCJournalLogEntryCollection(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002161{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002162 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002163 .privileges(redfish::privileges::getLogEntryCollection)
Ed Tanous002d39b2022-05-31 08:59:27 -07002164 .methods(boost::beast::http::verb::get)(
2165 [&app](const crow::Request& req,
2166 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2167 query_param::QueryCapabilities capabilities = {
2168 .canDelegateTop = true,
2169 .canDelegateSkip = true,
2170 };
2171 query_param::Query delegatedQuery;
2172 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00002173 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07002174 {
2175 return;
2176 }
2177 // Collections don't include the static data added by SubRoute
2178 // because it has a duplicate entry for members
2179 asyncResp->res.jsonValue["@odata.type"] =
2180 "#LogEntryCollection.LogEntryCollection";
2181 asyncResp->res.jsonValue["@odata.id"] =
2182 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
2183 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2184 asyncResp->res.jsonValue["Description"] =
2185 "Collection of BMC Journal Entries";
2186 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
2187 logEntryArray = nlohmann::json::array();
Jason M. Billse1f26342018-07-18 12:12:00 -07002188
Ed Tanous002d39b2022-05-31 08:59:27 -07002189 // Go through the journal and use the timestamp to create a
2190 // unique ID for each entry
2191 sd_journal* journalTmp = nullptr;
2192 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2193 if (ret < 0)
2194 {
2195 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2196 messages::internalError(asyncResp->res);
2197 return;
2198 }
2199 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2200 journalTmp, sd_journal_close);
2201 journalTmp = nullptr;
2202 uint64_t entryCount = 0;
2203 // Reset the unique ID on the first entry
2204 bool firstEntry = true;
2205 SD_JOURNAL_FOREACH(journal.get())
2206 {
2207 entryCount++;
2208 // Handle paging using skip (number of entries to skip from
2209 // the start) and top (number of entries to display)
2210 if (entryCount <= delegatedQuery.skip ||
2211 entryCount > delegatedQuery.skip + delegatedQuery.top)
George Liu0fda0f12021-11-16 10:06:17 +08002212 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002213 continue;
2214 }
2215
2216 std::string idStr;
2217 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2218 {
2219 continue;
2220 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002221 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002222
2223 logEntryArray.push_back({});
2224 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
2225 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2226 bmcJournalLogEntry) != 0)
2227 {
George Liu0fda0f12021-11-16 10:06:17 +08002228 messages::internalError(asyncResp->res);
2229 return;
2230 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002231 }
2232 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2233 if (delegatedQuery.skip + delegatedQuery.top < entryCount)
2234 {
2235 asyncResp->res.jsonValue["Members@odata.nextLink"] =
2236 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
2237 std::to_string(delegatedQuery.skip + delegatedQuery.top);
2238 }
George Liu0fda0f12021-11-16 10:06:17 +08002239 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002240}
Jason M. Billse1f26342018-07-18 12:12:00 -07002241
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002242inline void requestRoutesBMCJournalLogEntry(App& app)
Jason M. Billse1f26342018-07-18 12:12:00 -07002243{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002244 BMCWEB_ROUTE(app,
2245 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002246 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002247 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002248 [&app](const crow::Request& req,
2249 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2250 const std::string& entryID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002251 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002252 {
2253 return;
2254 }
2255 // Convert the unique ID back to a timestamp to find the entry
2256 uint64_t ts = 0;
2257 uint64_t index = 0;
2258 if (!getTimestampFromID(asyncResp, entryID, ts, index))
2259 {
2260 return;
2261 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002262
Ed Tanous002d39b2022-05-31 08:59:27 -07002263 sd_journal* journalTmp = nullptr;
2264 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2265 if (ret < 0)
2266 {
2267 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
2268 messages::internalError(asyncResp->res);
2269 return;
2270 }
2271 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2272 journalTmp, sd_journal_close);
2273 journalTmp = nullptr;
2274 // Go to the timestamp in the log and move to the entry at the
2275 // index tracking the unique ID
2276 std::string idStr;
2277 bool firstEntry = true;
2278 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
2279 if (ret < 0)
2280 {
2281 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2282 << strerror(-ret);
2283 messages::internalError(asyncResp->res);
2284 return;
2285 }
2286 for (uint64_t i = 0; i <= index; i++)
2287 {
2288 sd_journal_next(journal.get());
2289 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2290 {
2291 messages::internalError(asyncResp->res);
2292 return;
2293 }
Jason M. Billsefde4ec2022-06-24 08:59:52 -07002294 firstEntry = false;
Ed Tanous002d39b2022-05-31 08:59:27 -07002295 }
2296 // Confirm that the entry ID matches what was requested
2297 if (idStr != entryID)
2298 {
2299 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
2300 return;
2301 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002302
Ed Tanous002d39b2022-05-31 08:59:27 -07002303 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2304 asyncResp->res.jsonValue) != 0)
2305 {
2306 messages::internalError(asyncResp->res);
2307 return;
2308 }
2309 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002310}
2311
Claire Weinanfdd26902022-03-01 14:18:25 -08002312inline void
2313 getDumpServiceInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2314 const std::string& dumpType)
2315{
2316 std::string dumpPath;
2317 std::string overWritePolicy;
2318 bool collectDiagnosticDataSupported = false;
2319
2320 if (dumpType == "BMC")
2321 {
2322 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump";
2323 overWritePolicy = "WrapsWhenFull";
2324 collectDiagnosticDataSupported = true;
2325 }
2326 else if (dumpType == "FaultLog")
2327 {
2328 dumpPath = "/redfish/v1/Managers/bmc/LogServices/FaultLog";
2329 overWritePolicy = "Unknown";
2330 collectDiagnosticDataSupported = false;
2331 }
2332 else if (dumpType == "System")
2333 {
2334 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump";
2335 overWritePolicy = "WrapsWhenFull";
2336 collectDiagnosticDataSupported = true;
2337 }
2338 else
2339 {
2340 BMCWEB_LOG_ERROR << "getDumpServiceInfo() invalid dump type: "
2341 << dumpType;
2342 messages::internalError(asyncResp->res);
2343 return;
2344 }
2345
2346 asyncResp->res.jsonValue["@odata.id"] = dumpPath;
2347 asyncResp->res.jsonValue["@odata.type"] = "#LogService.v1_2_0.LogService";
2348 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2349 asyncResp->res.jsonValue["Description"] = dumpType + " Dump LogService";
2350 asyncResp->res.jsonValue["Id"] = std::filesystem::path(dumpPath).filename();
2351 asyncResp->res.jsonValue["OverWritePolicy"] = std::move(overWritePolicy);
2352
2353 std::pair<std::string, std::string> redfishDateTimeOffset =
2354 crow::utility::getDateTimeOffsetNow();
2355 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2356 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2357 redfishDateTimeOffset.second;
2358
2359 asyncResp->res.jsonValue["Entries"]["@odata.id"] = dumpPath + "/Entries";
2360 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2361 dumpPath + "/Actions/LogService.ClearLog";
2362
2363 if (collectDiagnosticDataSupported)
2364 {
2365 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2366 ["target"] =
2367 dumpPath + "/Actions/LogService.CollectDiagnosticData";
2368 }
2369}
2370
2371inline void handleLogServicesDumpServiceGet(
2372 crow::App& app, const std::string& dumpType, const crow::Request& req,
2373 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2374{
2375 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2376 {
2377 return;
2378 }
2379 getDumpServiceInfo(asyncResp, dumpType);
2380}
2381
2382inline void handleLogServicesDumpEntriesCollectionGet(
2383 crow::App& app, const std::string& dumpType, const crow::Request& req,
2384 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2385{
2386 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2387 {
2388 return;
2389 }
2390 getDumpEntryCollection(asyncResp, dumpType);
2391}
2392
2393inline void handleLogServicesDumpEntryGet(
2394 crow::App& app, const std::string& dumpType, const crow::Request& req,
2395 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2396 const std::string& dumpId)
2397{
2398 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2399 {
2400 return;
2401 }
2402 getDumpEntryById(asyncResp, dumpId, dumpType);
2403}
2404
2405inline void handleLogServicesDumpEntryDelete(
2406 crow::App& app, const std::string& dumpType, const crow::Request& req,
2407 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2408 const std::string& dumpId)
2409{
2410 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2411 {
2412 return;
2413 }
2414 deleteDumpEntry(asyncResp, dumpId, dumpType);
2415}
2416
2417inline void handleLogServicesDumpCollectDiagnosticDataPost(
2418 crow::App& app, const std::string& dumpType, const crow::Request& req,
2419 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2420{
2421 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2422 {
2423 return;
2424 }
2425 createDump(asyncResp, req, dumpType);
2426}
2427
2428inline void handleLogServicesDumpClearLogPost(
2429 crow::App& app, const std::string& dumpType, const crow::Request& req,
2430 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2431{
2432 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2433 {
2434 return;
2435 }
2436 clearDump(asyncResp, dumpType);
2437}
2438
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002439inline void requestRoutesBMCDumpService(App& app)
2440{
2441 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002442 .privileges(redfish::privileges::getLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002443 .methods(boost::beast::http::verb::get)(std::bind_front(
2444 handleLogServicesDumpServiceGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002445}
2446
2447inline void requestRoutesBMCDumpEntryCollection(App& app)
2448{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002449 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002450 .privileges(redfish::privileges::getLogEntryCollection)
Claire Weinanfdd26902022-03-01 14:18:25 -08002451 .methods(boost::beast::http::verb::get)(std::bind_front(
2452 handleLogServicesDumpEntriesCollectionGet, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002453}
2454
2455inline void requestRoutesBMCDumpEntry(App& app)
2456{
2457 BMCWEB_ROUTE(app,
2458 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002459 .privileges(redfish::privileges::getLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002460 .methods(boost::beast::http::verb::get)(std::bind_front(
2461 handleLogServicesDumpEntryGet, std::ref(app), "BMC"));
2462
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002463 BMCWEB_ROUTE(app,
2464 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002465 .privileges(redfish::privileges::deleteLogEntry)
Claire Weinanfdd26902022-03-01 14:18:25 -08002466 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2467 handleLogServicesDumpEntryDelete, std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002468}
2469
2470inline void requestRoutesBMCDumpCreate(App& app)
2471{
George Liu0fda0f12021-11-16 10:06:17 +08002472 BMCWEB_ROUTE(
2473 app,
2474 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002475 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002476 .methods(boost::beast::http::verb::post)(
Claire Weinanfdd26902022-03-01 14:18:25 -08002477 std::bind_front(handleLogServicesDumpCollectDiagnosticDataPost,
2478 std::ref(app), "BMC"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002479}
2480
2481inline void requestRoutesBMCDumpClear(App& app)
2482{
George Liu0fda0f12021-11-16 10:06:17 +08002483 BMCWEB_ROUTE(
2484 app,
2485 "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002486 .privileges(redfish::privileges::postLogService)
Claire Weinanfdd26902022-03-01 14:18:25 -08002487 .methods(boost::beast::http::verb::post)(std::bind_front(
2488 handleLogServicesDumpClearLogPost, std::ref(app), "BMC"));
2489}
2490
2491inline void requestRoutesFaultLogDumpService(App& app)
2492{
2493 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/")
2494 .privileges(redfish::privileges::getLogService)
2495 .methods(boost::beast::http::verb::get)(std::bind_front(
2496 handleLogServicesDumpServiceGet, std::ref(app), "FaultLog"));
2497}
2498
2499inline void requestRoutesFaultLogDumpEntryCollection(App& app)
2500{
2501 BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/")
2502 .privileges(redfish::privileges::getLogEntryCollection)
2503 .methods(boost::beast::http::verb::get)(
2504 std::bind_front(handleLogServicesDumpEntriesCollectionGet,
2505 std::ref(app), "FaultLog"));
2506}
2507
2508inline void requestRoutesFaultLogDumpEntry(App& app)
2509{
2510 BMCWEB_ROUTE(app,
2511 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2512 .privileges(redfish::privileges::getLogEntry)
2513 .methods(boost::beast::http::verb::get)(std::bind_front(
2514 handleLogServicesDumpEntryGet, std::ref(app), "FaultLog"));
2515
2516 BMCWEB_ROUTE(app,
2517 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Entries/<str>/")
2518 .privileges(redfish::privileges::deleteLogEntry)
2519 .methods(boost::beast::http::verb::delete_)(std::bind_front(
2520 handleLogServicesDumpEntryDelete, std::ref(app), "FaultLog"));
2521}
2522
2523inline void requestRoutesFaultLogDumpClear(App& app)
2524{
2525 BMCWEB_ROUTE(
2526 app,
2527 "/redfish/v1/Managers/bmc/LogServices/FaultLog/Actions/LogService.ClearLog/")
2528 .privileges(redfish::privileges::postLogService)
2529 .methods(boost::beast::http::verb::post)(std::bind_front(
2530 handleLogServicesDumpClearLogPost, std::ref(app), "FaultLog"));
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002531}
2532
2533inline void requestRoutesSystemDumpService(App& app)
2534{
2535 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/")
Ed Tanoused398212021-06-09 17:05:54 -07002536 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07002537 .methods(boost::beast::http::verb::get)(
2538 [&app](const crow::Request& req,
2539 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002540 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002541 {
2542 return;
2543 }
2544 asyncResp->res.jsonValue["@odata.id"] =
2545 "/redfish/v1/Systems/system/LogServices/Dump";
2546 asyncResp->res.jsonValue["@odata.type"] =
2547 "#LogService.v1_2_0.LogService";
2548 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2549 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2550 asyncResp->res.jsonValue["Id"] = "Dump";
2551 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Tejas Patil7c8c4052021-06-04 17:43:14 +05302552
Ed Tanous002d39b2022-05-31 08:59:27 -07002553 std::pair<std::string, std::string> redfishDateTimeOffset =
2554 crow::utility::getDateTimeOffsetNow();
2555 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2556 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2557 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302558
Ed Tanous002d39b2022-05-31 08:59:27 -07002559 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2560 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2561 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2562 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog";
Ed Tanous14766872022-03-15 10:44:42 -07002563
Ed Tanous002d39b2022-05-31 08:59:27 -07002564 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2565 ["target"] =
2566 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData";
Ed Tanous45ca1b82022-03-25 13:07:27 -07002567 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002568}
2569
2570inline void requestRoutesSystemDumpEntryCollection(App& app)
2571{
2572
2573 /**
2574 * Functions triggers appropriate requests on DBus
2575 */
Asmitha Karunanithib2a32892021-07-13 11:56:15 -05002576 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002577 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002578 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002579 [&app](const crow::Request& req,
2580 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002581 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002582 {
2583 return;
2584 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002585 getDumpEntryCollection(asyncResp, "System");
2586 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002587}
2588
2589inline void requestRoutesSystemDumpEntry(App& app)
2590{
2591 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002592 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002593 .privileges(redfish::privileges::getLogEntry)
2594
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002595 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002596 [&app](const crow::Request& req,
2597 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2598 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002599 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Claire Weinanc7a6d662022-06-13 16:36:39 -07002600 {
2601 return;
2602 }
2603 getDumpEntryById(asyncResp, param, "System");
Ed Tanous002d39b2022-05-31 08:59:27 -07002604 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002605
2606 BMCWEB_ROUTE(app,
John Edward Broadbent864d6a12021-06-09 10:12:48 -07002607 "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002608 .privileges(redfish::privileges::deleteLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002609 .methods(boost::beast::http::verb::delete_)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002610 [&app](const crow::Request& req,
2611 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2612 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002613 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002614 {
2615 return;
2616 }
2617 deleteDumpEntry(asyncResp, param, "system");
2618 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002619}
2620
2621inline void requestRoutesSystemDumpCreate(App& app)
2622{
George Liu0fda0f12021-11-16 10:06:17 +08002623 BMCWEB_ROUTE(
2624 app,
2625 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002626 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002627 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002628 [&app](const crow::Request& req,
2629 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002630 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002631 {
2632 return;
2633 }
2634 createDump(asyncResp, req, "System");
2635 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002636}
2637
2638inline void requestRoutesSystemDumpClear(App& app)
2639{
George Liu0fda0f12021-11-16 10:06:17 +08002640 BMCWEB_ROUTE(
2641 app,
2642 "/redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002643 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002644 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002645 [&app](const crow::Request& req,
2646 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002647
Ed Tanous45ca1b82022-03-25 13:07:27 -07002648 {
Carson Labrado3ba00072022-06-06 19:40:56 +00002649 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002650 {
2651 return;
2652 }
2653 clearDump(asyncResp, "System");
2654 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002655}
2656
2657inline void requestRoutesCrashdumpService(App& app)
2658{
2659 // Note: Deviated from redfish privilege registry for GET & HEAD
2660 // method for security reasons.
2661 /**
2662 * Functions triggers appropriate requests on DBus
2663 */
2664 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanoused398212021-06-09 17:05:54 -07002665 // This is incorrect, should be:
2666 //.privileges(redfish::privileges::getLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002667 .privileges({{"ConfigureManager"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002668 .methods(boost::beast::http::verb::get)(
2669 [&app](const crow::Request& req,
2670 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002671 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002672 {
2673 return;
2674 }
2675 // Copy over the static data to include the entries added by
2676 // SubRoute
2677 asyncResp->res.jsonValue["@odata.id"] =
2678 "/redfish/v1/Systems/system/LogServices/Crashdump";
2679 asyncResp->res.jsonValue["@odata.type"] =
2680 "#LogService.v1_2_0.LogService";
2681 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2682 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2683 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
2684 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2685 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302686
Ed Tanous002d39b2022-05-31 08:59:27 -07002687 std::pair<std::string, std::string> redfishDateTimeOffset =
2688 crow::utility::getDateTimeOffsetNow();
2689 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
2690 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
2691 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05302692
Ed Tanous002d39b2022-05-31 08:59:27 -07002693 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
2694 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2695 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"]["target"] =
2696 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog";
2697 asyncResp->res.jsonValue["Actions"]["#LogService.CollectDiagnosticData"]
2698 ["target"] =
2699 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData";
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002700 });
2701}
2702
2703void inline requestRoutesCrashdumpClear(App& app)
2704{
George Liu0fda0f12021-11-16 10:06:17 +08002705 BMCWEB_ROUTE(
2706 app,
2707 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07002708 // This is incorrect, should be:
2709 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002710 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002711 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002712 [&app](const crow::Request& req,
2713 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002714 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002715 {
2716 return;
2717 }
2718 crow::connections::systemBus->async_method_call(
2719 [asyncResp](const boost::system::error_code ec,
2720 const std::string&) {
2721 if (ec)
2722 {
2723 messages::internalError(asyncResp->res);
2724 return;
2725 }
2726 messages::success(asyncResp->res);
2727 },
2728 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2729 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002730}
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002731
zhanghch058d1b46d2021-04-01 11:18:24 +08002732static void
2733 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2734 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002735{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002736 auto getStoredLogCallback =
Ed Tanousb9d36b42022-02-26 21:42:46 -08002737 [asyncResp, logID,
2738 &logEntryJson](const boost::system::error_code ec,
2739 const dbus::utility::DBusPropertiesMap& params) {
Ed Tanous002d39b2022-05-31 08:59:27 -07002740 if (ec)
2741 {
2742 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2743 if (ec.value() ==
2744 boost::system::linux_error::bad_request_descriptor)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002745 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002746 messages::resourceNotFound(asyncResp->res, "LogEntry", logID);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002747 }
2748 else
2749 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002750 messages::internalError(asyncResp->res);
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002751 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002752 return;
2753 }
2754
2755 std::string timestamp{};
2756 std::string filename{};
2757 std::string logfile{};
2758 parseCrashdumpParameters(params, filename, timestamp, logfile);
2759
2760 if (filename.empty() || timestamp.empty())
2761 {
2762 messages::resourceMissingAtURI(asyncResp->res,
2763 crow::utility::urlFromPieces(logID));
2764 return;
2765 }
2766
2767 std::string crashdumpURI =
2768 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2769 logID + "/" + filename;
2770 nlohmann::json logEntry = {
2771 {"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
2772 {"@odata.id",
2773 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2774 logID},
2775 {"Name", "CPU Crashdump"},
2776 {"Id", logID},
2777 {"EntryType", "Oem"},
2778 {"AdditionalDataURI", std::move(crashdumpURI)},
2779 {"DiagnosticDataType", "OEM"},
2780 {"OEMDiagnosticDataType", "PECICrashdump"},
2781 {"Created", std::move(timestamp)}};
2782
2783 // If logEntryJson references an array of LogEntry resources
2784 // ('Members' list), then push this as a new entry, otherwise set it
2785 // directly
2786 if (logEntryJson.is_array())
2787 {
2788 logEntryJson.push_back(logEntry);
2789 asyncResp->res.jsonValue["Members@odata.count"] =
2790 logEntryJson.size();
2791 }
2792 else
2793 {
2794 logEntryJson = logEntry;
2795 }
2796 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002797 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002798 std::move(getStoredLogCallback), crashdumpObject,
2799 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002800 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002801}
2802
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002803inline void requestRoutesCrashdumpEntryCollection(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002804{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002805 // Note: Deviated from redfish privilege registry for GET & HEAD
2806 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002807 /**
2808 * Functions triggers appropriate requests on DBus
2809 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002810 BMCWEB_ROUTE(app,
2811 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07002812 // This is incorrect, should be.
2813 //.privileges(redfish::privileges::postLogEntryCollection)
Ed Tanous432a8902021-06-14 15:28:56 -07002814 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002815 .methods(boost::beast::http::verb::get)(
2816 [&app](const crow::Request& req,
2817 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002818 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002819 {
2820 return;
2821 }
2822 crow::connections::systemBus->async_method_call(
2823 [asyncResp](const boost::system::error_code ec,
2824 const std::vector<std::string>& resp) {
2825 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07002826 {
Ed Tanous002d39b2022-05-31 08:59:27 -07002827 if (ec.value() !=
2828 boost::system::errc::no_such_file_or_directory)
2829 {
2830 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2831 << ec.message();
2832 messages::internalError(asyncResp->res);
2833 return;
2834 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07002835 }
Ed Tanous002d39b2022-05-31 08:59:27 -07002836 asyncResp->res.jsonValue["@odata.type"] =
2837 "#LogEntryCollection.LogEntryCollection";
2838 asyncResp->res.jsonValue["@odata.id"] =
2839 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
2840 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
2841 asyncResp->res.jsonValue["Description"] =
2842 "Collection of Crashdump Entries";
2843 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
2844 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Jason M. Bills2b20ef62022-01-06 15:48:07 -08002845
Ed Tanous002d39b2022-05-31 08:59:27 -07002846 for (const std::string& path : resp)
2847 {
2848 const sdbusplus::message::object_path objPath(path);
2849 // Get the log ID
2850 std::string logID = objPath.filename();
2851 if (logID.empty())
2852 {
2853 continue;
2854 }
2855 // Add the log entry to the array
2856 logCrashdumpEntry(asyncResp, logID,
2857 asyncResp->res.jsonValue["Members"]);
2858 }
2859 },
2860 "xyz.openbmc_project.ObjectMapper",
2861 "/xyz/openbmc_project/object_mapper",
2862 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
2863 std::array<const char*, 1>{crashdumpInterface});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002864 });
2865}
Ed Tanous1da66f72018-07-27 16:13:37 -07002866
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002867inline void requestRoutesCrashdumpEntry(App& app)
Ed Tanous1da66f72018-07-27 16:13:37 -07002868{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002869 // Note: Deviated from redfish privilege registry for GET & HEAD
2870 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002871
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002872 BMCWEB_ROUTE(
2873 app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002874 // this is incorrect, should be
2875 // .privileges(redfish::privileges::getLogEntry)
Ed Tanous432a8902021-06-14 15:28:56 -07002876 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002877 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002878 [&app](const crow::Request& req,
2879 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2880 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002881 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002882 {
2883 return;
2884 }
2885 const std::string& logID = param;
2886 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2887 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002888}
Ed Tanous1da66f72018-07-27 16:13:37 -07002889
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002890inline void requestRoutesCrashdumpFile(App& app)
2891{
2892 // Note: Deviated from redfish privilege registry for GET & HEAD
2893 // method for security reasons.
2894 BMCWEB_ROUTE(
2895 app,
2896 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07002897 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002898 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07002899 [&app](const crow::Request& req,
2900 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2901 const std::string& logID, const std::string& fileName) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002902 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002903 {
2904 return;
2905 }
2906 auto getStoredLogCallback =
2907 [asyncResp, logID, fileName, url(boost::urls::url(req.urlView))](
2908 const boost::system::error_code ec,
2909 const std::vector<
2910 std::pair<std::string, dbus::utility::DbusVariantType>>&
2911 resp) {
2912 if (ec)
2913 {
2914 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2915 messages::internalError(asyncResp->res);
2916 return;
2917 }
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002918
Ed Tanous002d39b2022-05-31 08:59:27 -07002919 std::string dbusFilename{};
2920 std::string dbusTimestamp{};
2921 std::string dbusFilepath{};
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002922
Ed Tanous002d39b2022-05-31 08:59:27 -07002923 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
2924 dbusFilepath);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002925
Ed Tanous002d39b2022-05-31 08:59:27 -07002926 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2927 dbusFilepath.empty())
2928 {
2929 messages::resourceMissingAtURI(asyncResp->res, url);
2930 return;
2931 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002932
Ed Tanous002d39b2022-05-31 08:59:27 -07002933 // Verify the file name parameter is correct
2934 if (fileName != dbusFilename)
2935 {
2936 messages::resourceMissingAtURI(asyncResp->res, url);
2937 return;
2938 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002939
Ed Tanous002d39b2022-05-31 08:59:27 -07002940 if (!std::filesystem::exists(dbusFilepath))
2941 {
2942 messages::resourceMissingAtURI(asyncResp->res, url);
2943 return;
2944 }
2945 std::ifstream ifs(dbusFilepath, std::ios::in | std::ios::binary);
2946 asyncResp->res.body() =
2947 std::string(std::istreambuf_iterator<char>{ifs}, {});
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002948
Ed Tanous002d39b2022-05-31 08:59:27 -07002949 // Configure this to be a file download when accessed
2950 // from a browser
2951 asyncResp->res.addHeader("Content-Disposition", "attachment");
2952 };
2953 crow::connections::systemBus->async_method_call(
2954 std::move(getStoredLogCallback), crashdumpObject,
2955 crashdumpPath + std::string("/") + logID,
2956 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
2957 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002958}
2959
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002960enum class OEMDiagnosticType
2961{
2962 onDemand,
2963 telemetry,
2964 invalid,
2965};
2966
Ed Tanousf7725d72022-03-07 12:46:00 -08002967inline OEMDiagnosticType
2968 getOEMDiagnosticType(const std::string_view& oemDiagStr)
Jason M. Billsc5a4c822022-01-06 15:51:23 -08002969{
2970 if (oemDiagStr == "OnDemand")
2971 {
2972 return OEMDiagnosticType::onDemand;
2973 }
2974 if (oemDiagStr == "Telemetry")
2975 {
2976 return OEMDiagnosticType::telemetry;
2977 }
2978
2979 return OEMDiagnosticType::invalid;
2980}
2981
John Edward Broadbent7e860f12021-04-08 15:57:16 -07002982inline void requestRoutesCrashdumpCollect(App& app)
2983{
2984 // Note: Deviated from redfish privilege registry for GET & HEAD
2985 // method for security reasons.
George Liu0fda0f12021-11-16 10:06:17 +08002986 BMCWEB_ROUTE(
2987 app,
2988 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/LogService.CollectDiagnosticData/")
Ed Tanoused398212021-06-09 17:05:54 -07002989 // The below is incorrect; Should be ConfigureManager
2990 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07002991 .privileges({{"ConfigureComponents"}})
Ed Tanous002d39b2022-05-31 08:59:27 -07002992 .methods(boost::beast::http::verb::post)(
2993 [&app](const crow::Request& req,
2994 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00002995 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07002996 {
2997 return;
2998 }
2999 std::string diagnosticDataType;
3000 std::string oemDiagnosticDataType;
3001 if (!redfish::json_util::readJsonAction(
3002 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
3003 "OEMDiagnosticDataType", oemDiagnosticDataType))
3004 {
3005 return;
3006 }
3007
3008 if (diagnosticDataType != "OEM")
3009 {
3010 BMCWEB_LOG_ERROR
3011 << "Only OEM DiagnosticDataType supported for Crashdump";
3012 messages::actionParameterValueFormatError(
3013 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
3014 "CollectDiagnosticData");
3015 return;
3016 }
3017
3018 OEMDiagnosticType oemDiagType =
3019 getOEMDiagnosticType(oemDiagnosticDataType);
3020
3021 std::string iface;
3022 std::string method;
3023 std::string taskMatchStr;
3024 if (oemDiagType == OEMDiagnosticType::onDemand)
3025 {
3026 iface = crashdumpOnDemandInterface;
3027 method = "GenerateOnDemandLog";
3028 taskMatchStr = "type='signal',"
3029 "interface='org.freedesktop.DBus.Properties',"
3030 "member='PropertiesChanged',"
3031 "arg0namespace='com.intel.crashdump'";
3032 }
3033 else if (oemDiagType == OEMDiagnosticType::telemetry)
3034 {
3035 iface = crashdumpTelemetryInterface;
3036 method = "GenerateTelemetryLog";
3037 taskMatchStr = "type='signal',"
3038 "interface='org.freedesktop.DBus.Properties',"
3039 "member='PropertiesChanged',"
3040 "arg0namespace='com.intel.crashdump'";
3041 }
3042 else
3043 {
3044 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3045 << oemDiagnosticDataType;
3046 messages::actionParameterValueFormatError(
3047 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3048 "CollectDiagnosticData");
3049 return;
3050 }
3051
3052 auto collectCrashdumpCallback =
3053 [asyncResp, payload(task::Payload(req)),
3054 taskMatchStr](const boost::system::error_code ec,
3055 const std::string&) mutable {
3056 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -07003057 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003058 if (ec.value() == boost::system::errc::operation_not_supported)
3059 {
3060 messages::resourceInStandby(asyncResp->res);
3061 }
3062 else if (ec.value() ==
3063 boost::system::errc::device_or_resource_busy)
3064 {
3065 messages::serviceTemporarilyUnavailable(asyncResp->res,
3066 "60");
3067 }
3068 else
3069 {
3070 messages::internalError(asyncResp->res);
3071 }
Ed Tanous45ca1b82022-03-25 13:07:27 -07003072 return;
3073 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003074 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
3075 [](boost::system::error_code err, sdbusplus::message::message&,
3076 const std::shared_ptr<task::TaskData>& taskData) {
3077 if (!err)
3078 {
3079 taskData->messages.emplace_back(messages::taskCompletedOK(
3080 std::to_string(taskData->index)));
3081 taskData->state = "Completed";
3082 }
3083 return task::completed;
3084 },
3085 taskMatchStr);
Ed Tanous1da66f72018-07-27 16:13:37 -07003086
Ed Tanous002d39b2022-05-31 08:59:27 -07003087 task->startTimer(std::chrono::minutes(5));
3088 task->populateResp(asyncResp->res);
3089 task->payload.emplace(std::move(payload));
3090 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003091
Ed Tanous002d39b2022-05-31 08:59:27 -07003092 crow::connections::systemBus->async_method_call(
3093 std::move(collectCrashdumpCallback), crashdumpObject, crashdumpPath,
3094 iface, method);
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003095 });
3096}
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003097
Andrew Geisslercb92c032018-08-17 07:56:14 -07003098/**
3099 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3100 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003101inline void requestRoutesDBusLogServiceActionsClear(App& app)
Andrew Geisslercb92c032018-08-17 07:56:14 -07003102{
Andrew Geisslercb92c032018-08-17 07:56:14 -07003103 /**
3104 * Function handles POST method request.
3105 * The Clear Log actions does not require any parameter.The action deletes
3106 * all entries found in the Entries collection for this Log Service.
3107 */
Andrew Geisslercb92c032018-08-17 07:56:14 -07003108
George Liu0fda0f12021-11-16 10:06:17 +08003109 BMCWEB_ROUTE(
3110 app,
3111 "/redfish/v1/Systems/system/LogServices/EventLog/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003112 .privileges(redfish::privileges::postLogService)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003113 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003114 [&app](const crow::Request& req,
3115 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003116 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003117 {
3118 return;
3119 }
3120 BMCWEB_LOG_DEBUG << "Do delete all entries.";
Andrew Geisslercb92c032018-08-17 07:56:14 -07003121
Ed Tanous002d39b2022-05-31 08:59:27 -07003122 // Process response from Logging service.
3123 auto respHandler = [asyncResp](const boost::system::error_code ec) {
3124 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3125 if (ec)
3126 {
3127 // TODO Handle for specific error code
3128 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3129 asyncResp->res.result(
3130 boost::beast::http::status::internal_server_error);
3131 return;
3132 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07003133
Ed Tanous002d39b2022-05-31 08:59:27 -07003134 asyncResp->res.result(boost::beast::http::status::no_content);
3135 };
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003136
Ed Tanous002d39b2022-05-31 08:59:27 -07003137 // Make call to Logging service to request Clear Log
3138 crow::connections::systemBus->async_method_call(
3139 respHandler, "xyz.openbmc_project.Logging",
3140 "/xyz/openbmc_project/logging",
3141 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3142 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003143}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003144
3145/****************************************************
3146 * Redfish PostCode interfaces
3147 * using DBUS interface: getPostCodesTS
3148 ******************************************************/
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003149inline void requestRoutesPostCodesLogService(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003150{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003151 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
Ed Tanoused398212021-06-09 17:05:54 -07003152 .privileges(redfish::privileges::getLogService)
Ed Tanous002d39b2022-05-31 08:59:27 -07003153 .methods(boost::beast::http::verb::get)(
3154 [&app](const crow::Request& req,
3155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003156 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003157 {
3158 return;
3159 }
Ed Tanous14766872022-03-15 10:44:42 -07003160
Ed Tanous002d39b2022-05-31 08:59:27 -07003161 asyncResp->res.jsonValue["@odata.id"] =
3162 "/redfish/v1/Systems/system/LogServices/PostCodes";
3163 asyncResp->res.jsonValue["@odata.type"] =
3164 "#LogService.v1_1_0.LogService";
3165 asyncResp->res.jsonValue["Name"] = "POST Code Log Service";
3166 asyncResp->res.jsonValue["Description"] = "POST Code Log Service";
3167 asyncResp->res.jsonValue["Id"] = "BIOS POST Code Log";
3168 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
3169 asyncResp->res.jsonValue["Entries"]["@odata.id"] =
3170 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
Tejas Patil7c8c4052021-06-04 17:43:14 +05303171
Ed Tanous002d39b2022-05-31 08:59:27 -07003172 std::pair<std::string, std::string> redfishDateTimeOffset =
3173 crow::utility::getDateTimeOffsetNow();
3174 asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first;
3175 asyncResp->res.jsonValue["DateTimeLocalOffset"] =
3176 redfishDateTimeOffset.second;
Tejas Patil7c8c4052021-06-04 17:43:14 +05303177
Ed Tanous002d39b2022-05-31 08:59:27 -07003178 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3179 {"target",
3180 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog"}};
George Liu0fda0f12021-11-16 10:06:17 +08003181 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003182}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003183
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003184inline void requestRoutesPostCodesClear(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003185{
George Liu0fda0f12021-11-16 10:06:17 +08003186 BMCWEB_ROUTE(
3187 app,
3188 "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/LogService.ClearLog/")
Ed Tanoused398212021-06-09 17:05:54 -07003189 // The following privilege is incorrect; It should be ConfigureManager
3190 //.privileges(redfish::privileges::postLogService)
Ed Tanous432a8902021-06-14 15:28:56 -07003191 .privileges({{"ConfigureComponents"}})
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003192 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003193 [&app](const crow::Request& req,
3194 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003195 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003196 {
3197 return;
3198 }
3199 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003200
Ed Tanous002d39b2022-05-31 08:59:27 -07003201 // Make call to post-code service to request clear all
3202 crow::connections::systemBus->async_method_call(
3203 [asyncResp](const boost::system::error_code ec) {
3204 if (ec)
3205 {
3206 // TODO Handle for specific error code
3207 BMCWEB_LOG_ERROR << "doClearPostCodes resp_handler got error "
3208 << ec;
3209 asyncResp->res.result(
3210 boost::beast::http::status::internal_server_error);
3211 messages::internalError(asyncResp->res);
3212 return;
3213 }
3214 },
3215 "xyz.openbmc_project.State.Boot.PostCode0",
3216 "/xyz/openbmc_project/State/Boot/PostCode0",
3217 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3218 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003219}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003220
3221static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003222 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303223 const boost::container::flat_map<
3224 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003225 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3226 const uint64_t skip = 0, const uint64_t top = 0)
3227{
3228 // Get the Message from the MessageRegistry
Ed Tanousfffb8c12022-02-07 23:53:03 -08003229 const registries::Message* message =
3230 registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003231
3232 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003233 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003234
3235 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303236 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3237 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003238 {
3239 currentCodeIndex++;
3240 std::string postcodeEntryID =
3241 "B" + std::to_string(bootIndex) + "-" +
3242 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3243
3244 uint64_t usecSinceEpoch = code.first;
3245 uint64_t usTimeOffset = 0;
3246
3247 if (1 == currentCodeIndex)
3248 { // already incremented
3249 firstCodeTimeUs = code.first;
3250 }
3251 else
3252 {
3253 usTimeOffset = code.first - firstCodeTimeUs;
3254 }
3255
3256 // skip if no specific codeIndex is specified and currentCodeIndex does
3257 // not fall between top and skip
3258 if ((codeIndex == 0) &&
3259 (currentCodeIndex <= skip || currentCodeIndex > top))
3260 {
3261 continue;
3262 }
3263
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003264 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003265 // currentIndex
3266 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3267 {
3268 // This is done for simplicity. 1st entry is needed to calculate
3269 // time offset. To improve efficiency, one can get to the entry
3270 // directly (possibly with flatmap's nth method)
3271 continue;
3272 }
3273
3274 // currentCodeIndex is within top and skip or equal to specified code
3275 // index
3276
3277 // Get the Created time from the timestamp
3278 std::string entryTimeStr;
Nan Zhou1d8782e2021-11-29 22:23:18 -08003279 entryTimeStr =
3280 crow::utility::getDateTimeUint(usecSinceEpoch / 1000 / 1000);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003281
3282 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3283 std::ostringstream hexCode;
3284 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303285 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003286 std::ostringstream timeOffsetStr;
3287 // Set Fixed -Point Notation
3288 timeOffsetStr << std::fixed;
3289 // Set precision to 4 digits
3290 timeOffsetStr << std::setprecision(4);
3291 // Add double to stream
3292 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3293 std::vector<std::string> messageArgs = {
3294 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3295
3296 // Get MessageArgs template from message registry
3297 std::string msg;
3298 if (message != nullptr)
3299 {
3300 msg = message->message;
3301
3302 // fill in this post code value
3303 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003304 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003305 {
3306 std::string argStr = "%" + std::to_string(++i);
3307 size_t argPos = msg.find(argStr);
3308 if (argPos != std::string::npos)
3309 {
3310 msg.replace(argPos, argStr.length(), messageArg);
3311 }
3312 }
3313 }
3314
Tim Leed4342a92020-04-27 11:47:58 +08003315 // Get Severity template from message registry
3316 std::string severity;
3317 if (message != nullptr)
3318 {
Ed Tanous5f2b84e2022-02-08 00:41:53 -08003319 severity = message->messageSeverity;
Tim Leed4342a92020-04-27 11:47:58 +08003320 }
3321
ZhikuiRena3316fc2020-01-29 14:58:08 -08003322 // add to AsyncResp
3323 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003324 nlohmann::json& bmcLogEntry = logEntryArray.back();
George Liu0fda0f12021-11-16 10:06:17 +08003325 bmcLogEntry = {
3326 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
3327 {"@odata.id",
3328 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3329 postcodeEntryID},
3330 {"Name", "POST Code Log Entry"},
3331 {"Id", postcodeEntryID},
3332 {"Message", std::move(msg)},
3333 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
3334 {"MessageArgs", std::move(messageArgs)},
3335 {"EntryType", "Event"},
3336 {"Severity", std::move(severity)},
3337 {"Created", entryTimeStr}};
George Liu647b3cd2021-07-05 12:43:56 +08003338 if (!std::get<std::vector<uint8_t>>(code.second).empty())
3339 {
3340 bmcLogEntry["AdditionalDataURI"] =
3341 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/" +
3342 postcodeEntryID + "/attachment";
3343 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003344 }
3345}
3346
zhanghch058d1b46d2021-04-01 11:18:24 +08003347static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003348 const uint16_t bootIndex,
3349 const uint64_t codeIndex)
3350{
3351 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303352 [aResp, bootIndex,
3353 codeIndex](const boost::system::error_code ec,
3354 const boost::container::flat_map<
3355 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3356 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003357 if (ec)
3358 {
3359 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3360 messages::internalError(aResp->res);
3361 return;
3362 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003363
Ed Tanous002d39b2022-05-31 08:59:27 -07003364 // skip the empty postcode boots
3365 if (postcode.empty())
3366 {
3367 return;
3368 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003369
Ed Tanous002d39b2022-05-31 08:59:27 -07003370 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003371
Ed Tanous002d39b2022-05-31 08:59:27 -07003372 aResp->res.jsonValue["Members@odata.count"] =
3373 aResp->res.jsonValue["Members"].size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003374 },
Jonathan Doman15124762021-01-07 17:54:17 -08003375 "xyz.openbmc_project.State.Boot.PostCode0",
3376 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003377 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3378 bootIndex);
3379}
3380
zhanghch058d1b46d2021-04-01 11:18:24 +08003381static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003382 const uint16_t bootIndex,
3383 const uint16_t bootCount,
3384 const uint64_t entryCount, const uint64_t skip,
3385 const uint64_t top)
3386{
3387 crow::connections::systemBus->async_method_call(
3388 [aResp, bootIndex, bootCount, entryCount, skip,
3389 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303390 const boost::container::flat_map<
3391 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3392 postcode) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003393 if (ec)
3394 {
3395 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3396 messages::internalError(aResp->res);
3397 return;
3398 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003399
Ed Tanous002d39b2022-05-31 08:59:27 -07003400 uint64_t endCount = entryCount;
3401 if (!postcode.empty())
3402 {
3403 endCount = entryCount + postcode.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -08003404
Ed Tanous002d39b2022-05-31 08:59:27 -07003405 if ((skip < endCount) && ((top + skip) > entryCount))
ZhikuiRena3316fc2020-01-29 14:58:08 -08003406 {
Ed Tanous002d39b2022-05-31 08:59:27 -07003407 uint64_t thisBootSkip = std::max(skip, entryCount) - entryCount;
3408 uint64_t thisBootTop =
3409 std::min(top + skip, endCount) - entryCount;
3410
3411 fillPostCodeEntry(aResp, postcode, bootIndex, 0, thisBootSkip,
3412 thisBootTop);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003413 }
Ed Tanous002d39b2022-05-31 08:59:27 -07003414 aResp->res.jsonValue["Members@odata.count"] = endCount;
3415 }
3416
3417 // continue to previous bootIndex
3418 if (bootIndex < bootCount)
3419 {
3420 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3421 bootCount, endCount, skip, top);
3422 }
3423 else
3424 {
3425 aResp->res.jsonValue["Members@odata.nextLink"] =
3426 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries?$skip=" +
3427 std::to_string(skip + top);
3428 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003429 },
Jonathan Doman15124762021-01-07 17:54:17 -08003430 "xyz.openbmc_project.State.Boot.PostCode0",
3431 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003432 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3433 bootIndex);
3434}
3435
zhanghch058d1b46d2021-04-01 11:18:24 +08003436static void
3437 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3438 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003439{
3440 uint64_t entryCount = 0;
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003441 sdbusplus::asio::getProperty<uint16_t>(
3442 *crow::connections::systemBus,
3443 "xyz.openbmc_project.State.Boot.PostCode0",
3444 "/xyz/openbmc_project/State/Boot/PostCode0",
3445 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount",
3446 [aResp, entryCount, skip, top](const boost::system::error_code ec,
3447 const uint16_t bootCount) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003448 if (ec)
3449 {
3450 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3451 messages::internalError(aResp->res);
3452 return;
3453 }
3454 getPostCodeForBoot(aResp, 1, bootCount, entryCount, skip, top);
Jonathan Doman1e1e5982021-06-11 09:36:17 -07003455 });
ZhikuiRena3316fc2020-01-29 14:58:08 -08003456}
3457
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003458inline void requestRoutesPostCodesEntryCollection(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003459{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003460 BMCWEB_ROUTE(app,
3461 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
Ed Tanoused398212021-06-09 17:05:54 -07003462 .privileges(redfish::privileges::getLogEntryCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003463 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003464 [&app](const crow::Request& req,
3465 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -07003466 query_param::QueryCapabilities capabilities = {
3467 .canDelegateTop = true,
3468 .canDelegateSkip = true,
3469 };
3470 query_param::Query delegatedQuery;
3471 if (!redfish::setUpRedfishRouteWithDelegation(
Carson Labrado3ba00072022-06-06 19:40:56 +00003472 app, req, asyncResp, delegatedQuery, capabilities))
Ed Tanous002d39b2022-05-31 08:59:27 -07003473 {
3474 return;
3475 }
3476 asyncResp->res.jsonValue["@odata.type"] =
3477 "#LogEntryCollection.LogEntryCollection";
3478 asyncResp->res.jsonValue["@odata.id"] =
3479 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3480 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3481 asyncResp->res.jsonValue["Description"] =
3482 "Collection of POST Code Log Entries";
3483 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3484 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003485
Ed Tanous002d39b2022-05-31 08:59:27 -07003486 getCurrentBootNumber(asyncResp, delegatedQuery.skip,
3487 delegatedQuery.top);
3488 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003489}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003490
George Liu647b3cd2021-07-05 12:43:56 +08003491/**
3492 * @brief Parse post code ID and get the current value and index value
3493 * eg: postCodeID=B1-2, currentValue=1, index=2
3494 *
3495 * @param[in] postCodeID Post Code ID
3496 * @param[out] currentValue Current value
3497 * @param[out] index Index value
3498 *
3499 * @return bool true if the parsing is successful, false the parsing fails
3500 */
3501inline static bool parsePostCode(const std::string& postCodeID,
3502 uint64_t& currentValue, uint16_t& index)
3503{
3504 std::vector<std::string> split;
3505 boost::algorithm::split(split, postCodeID, boost::is_any_of("-"));
3506 if (split.size() != 2 || split[0].length() < 2 || split[0].front() != 'B')
3507 {
3508 return false;
3509 }
3510
Ed Tanousca45aa32022-01-07 09:28:45 -08003511 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003512 const char* start = split[0].data() + 1;
Ed Tanousca45aa32022-01-07 09:28:45 -08003513 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003514 const char* end = split[0].data() + split[0].size();
3515 auto [ptrIndex, ecIndex] = std::from_chars(start, end, index);
3516
3517 if (ptrIndex != end || ecIndex != std::errc())
3518 {
3519 return false;
3520 }
3521
3522 start = split[1].data();
Ed Tanousca45aa32022-01-07 09:28:45 -08003523
3524 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
George Liu647b3cd2021-07-05 12:43:56 +08003525 end = split[1].data() + split[1].size();
3526 auto [ptrValue, ecValue] = std::from_chars(start, end, currentValue);
George Liu647b3cd2021-07-05 12:43:56 +08003527
Ed Tanousdcf2ebc2022-01-25 10:07:45 -08003528 return ptrValue == end && ecValue != std::errc();
George Liu647b3cd2021-07-05 12:43:56 +08003529}
3530
3531inline void requestRoutesPostCodesEntryAdditionalData(App& app)
3532{
George Liu0fda0f12021-11-16 10:06:17 +08003533 BMCWEB_ROUTE(
3534 app,
3535 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/attachment/")
George Liu647b3cd2021-07-05 12:43:56 +08003536 .privileges(redfish::privileges::getLogEntry)
3537 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003538 [&app](const crow::Request& req,
3539 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3540 const std::string& postCodeID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003541 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003542 {
3543 return;
3544 }
3545 if (!http_helpers::isOctetAccepted(req.getHeaderValue("Accept")))
3546 {
3547 asyncResp->res.result(boost::beast::http::status::bad_request);
3548 return;
3549 }
George Liu647b3cd2021-07-05 12:43:56 +08003550
Ed Tanous002d39b2022-05-31 08:59:27 -07003551 uint64_t currentValue = 0;
3552 uint16_t index = 0;
3553 if (!parsePostCode(postCodeID, currentValue, index))
3554 {
3555 messages::resourceNotFound(asyncResp->res, "LogEntry", postCodeID);
3556 return;
3557 }
George Liu647b3cd2021-07-05 12:43:56 +08003558
Ed Tanous002d39b2022-05-31 08:59:27 -07003559 crow::connections::systemBus->async_method_call(
3560 [asyncResp, postCodeID, currentValue](
3561 const boost::system::error_code ec,
3562 const std::vector<std::tuple<uint64_t, std::vector<uint8_t>>>&
3563 postcodes) {
3564 if (ec.value() == EBADR)
3565 {
3566 messages::resourceNotFound(asyncResp->res, "LogEntry",
3567 postCodeID);
3568 return;
3569 }
3570 if (ec)
3571 {
3572 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3573 messages::internalError(asyncResp->res);
3574 return;
3575 }
George Liu647b3cd2021-07-05 12:43:56 +08003576
Ed Tanous002d39b2022-05-31 08:59:27 -07003577 size_t value = static_cast<size_t>(currentValue) - 1;
3578 if (value == std::string::npos || postcodes.size() < currentValue)
3579 {
3580 BMCWEB_LOG_ERROR << "Wrong currentValue value";
3581 messages::resourceNotFound(asyncResp->res, "LogEntry",
3582 postCodeID);
3583 return;
3584 }
George Liu647b3cd2021-07-05 12:43:56 +08003585
Ed Tanous002d39b2022-05-31 08:59:27 -07003586 const auto& [tID, c] = postcodes[value];
3587 if (c.empty())
3588 {
3589 BMCWEB_LOG_INFO << "No found post code data";
3590 messages::resourceNotFound(asyncResp->res, "LogEntry",
3591 postCodeID);
3592 return;
3593 }
3594 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
3595 const char* d = reinterpret_cast<const char*>(c.data());
3596 std::string_view strData(d, c.size());
George Liu647b3cd2021-07-05 12:43:56 +08003597
Ed Tanous002d39b2022-05-31 08:59:27 -07003598 asyncResp->res.addHeader("Content-Type",
3599 "application/octet-stream");
3600 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
3601 asyncResp->res.body() = crow::utility::base64encode(strData);
3602 },
3603 "xyz.openbmc_project.State.Boot.PostCode0",
3604 "/xyz/openbmc_project/State/Boot/PostCode0",
3605 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodes", index);
3606 });
George Liu647b3cd2021-07-05 12:43:56 +08003607}
3608
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003609inline void requestRoutesPostCodesEntry(App& app)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003610{
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003611 BMCWEB_ROUTE(
3612 app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -07003613 .privileges(redfish::privileges::getLogEntry)
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003614 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -07003615 [&app](const crow::Request& req,
3616 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3617 const std::string& targetID) {
Carson Labrado3ba00072022-06-06 19:40:56 +00003618 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -07003619 {
3620 return;
3621 }
3622 uint16_t bootIndex = 0;
3623 uint64_t codeIndex = 0;
3624 if (!parsePostCode(targetID, codeIndex, bootIndex))
3625 {
3626 // Requested ID was not found
3627 messages::resourceMissingAtURI(asyncResp->res, req.urlView);
3628 return;
3629 }
3630 if (bootIndex == 0 || codeIndex == 0)
3631 {
3632 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3633 << targetID;
3634 }
ZhikuiRena3316fc2020-01-29 14:58:08 -08003635
Ed Tanous002d39b2022-05-31 08:59:27 -07003636 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
3637 asyncResp->res.jsonValue["@odata.id"] =
3638 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3639 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3640 asyncResp->res.jsonValue["Description"] =
3641 "Collection of POST Code Log Entries";
3642 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3643 asyncResp->res.jsonValue["Members@odata.count"] = 0;
ZhikuiRena3316fc2020-01-29 14:58:08 -08003644
Ed Tanous002d39b2022-05-31 08:59:27 -07003645 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3646 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -07003647}
ZhikuiRena3316fc2020-01-29 14:58:08 -08003648
Ed Tanous1da66f72018-07-27 16:13:37 -07003649} // namespace redfish