blob: 47d61c035039343adb1d6d5dd3201f335ba1af8c [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
18#include "node.hpp"
Jason M. Bills4851d452019-03-28 11:27:48 -070019#include "registries.hpp"
20#include "registries/base_message_registry.hpp"
21#include "registries/openbmc_message_registry.hpp"
James Feist46229572020-02-19 15:11:58 -080022#include "task.hpp"
Ed Tanous1da66f72018-07-27 16:13:37 -070023
Jason M. Billse1f26342018-07-18 12:12:00 -070024#include <systemd/sd-journal.h>
25
Jason M. Bills4851d452019-03-28 11:27:48 -070026#include <boost/algorithm/string/split.hpp>
27#include <boost/beast/core/span.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070028#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080029#include <boost/system/linux_error.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070030#include <error_messages.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050031
James Feist4418c7f2019-04-15 11:09:15 -070032#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080033#include <optional>
Jason M. Billscd225da2019-05-08 15:31:57 -070034#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080035#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070036
37namespace redfish
38{
39
Gunnar Mills1214b7e2020-06-04 10:11:30 -050040constexpr char const* crashdumpObject = "com.intel.crashdump";
41constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050042constexpr char const* crashdumpInterface = "com.intel.crashdump";
43constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070044 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070046 "com.intel.crashdump.OnDemand";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050047constexpr char const* crashdumpRawPECIInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070048 "com.intel.crashdump.SendRawPeci";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070049constexpr char const* crashdumpTelemetryInterface =
50 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070051
Jason M. Bills4851d452019-03-28 11:27:48 -070052namespace message_registries
53{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050054static const Message* getMessageFromRegistry(
55 const std::string& messageKey,
Jason M. Bills4851d452019-03-28 11:27:48 -070056 const boost::beast::span<const MessageEntry> registry)
57{
58 boost::beast::span<const MessageEntry>::const_iterator messageIt =
59 std::find_if(registry.cbegin(), registry.cend(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -050060 [&messageKey](const MessageEntry& messageEntry) {
Jason M. Bills4851d452019-03-28 11:27:48 -070061 return !std::strcmp(messageEntry.first,
62 messageKey.c_str());
63 });
64 if (messageIt != registry.cend())
65 {
66 return &messageIt->second;
67 }
68
69 return nullptr;
70}
71
Gunnar Mills1214b7e2020-06-04 10:11:30 -050072static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070073{
74 // Redfish MessageIds are in the form
75 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
76 // the right Message
77 std::vector<std::string> fields;
78 fields.reserve(4);
79 boost::split(fields, messageID, boost::is_any_of("."));
Gunnar Mills1214b7e2020-06-04 10:11:30 -050080 std::string& registryName = fields[0];
81 std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070082
83 // Find the right registry and check it for the MessageKey
84 if (std::string(base::header.registryPrefix) == registryName)
85 {
86 return getMessageFromRegistry(
87 messageKey, boost::beast::span<const MessageEntry>(base::registry));
88 }
89 if (std::string(openbmc::header.registryPrefix) == registryName)
90 {
91 return getMessageFromRegistry(
92 messageKey,
93 boost::beast::span<const MessageEntry>(openbmc::registry));
94 }
95 return nullptr;
96}
97} // namespace message_registries
98
James Feistf6150402019-01-08 10:36:20 -080099namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700100
Andrew Geisslercb92c032018-08-17 07:56:14 -0700101using GetManagedPropertyType = boost::container::flat_map<
Patrick Williams19bd78d2020-05-13 17:38:24 -0500102 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
103 int32_t, uint32_t, int64_t, uint64_t, double>>;
Andrew Geisslercb92c032018-08-17 07:56:14 -0700104
105using GetManagedObjectsType = boost::container::flat_map<
106 sdbusplus::message::object_path,
107 boost::container::flat_map<std::string, GetManagedPropertyType>>;
108
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500109inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700110{
Ed Tanousd4d25792020-09-29 15:15:03 -0700111 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
112 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
113 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
114 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700115 {
116 return "Critical";
117 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700118 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
119 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
120 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700121 {
122 return "OK";
123 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700124 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700125 {
126 return "Warning";
127 }
128 return "";
129}
130
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500131static int getJournalMetadata(sd_journal* journal,
132 const std::string_view& field,
133 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700134{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500135 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700136 size_t length = 0;
137 int ret = 0;
138 // Get the metadata from the requested field of the journal entry
Ed Tanous271584a2019-07-09 16:24:22 -0700139 ret = sd_journal_get_data(journal, field.data(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500140 reinterpret_cast<const void**>(&data), &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
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500151static int getJournalMetadata(sd_journal* journal,
152 const std::string_view& field, const int& base,
153 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
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500167static bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800168{
169 int ret = 0;
170 uint64_t timestamp = 0;
171 ret = sd_journal_get_realtime_usec(journal, &timestamp);
172 if (ret < 0)
173 {
174 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
175 << strerror(-ret);
176 return false;
177 }
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500178 entryTimestamp = crow::utility::getDateTime(
179 static_cast<std::time_t>(timestamp / 1000 / 1000));
180 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800181}
182
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500183static bool getSkipParam(crow::Response& res, const crow::Request& req,
184 uint64_t& skip)
Jason M. Bills16428a12018-11-02 12:42:29 -0700185{
James Feist5a7e8772020-07-22 09:08:38 -0700186 boost::urls::url_view::params_type::iterator it =
187 req.urlParams.find("$skip");
188 if (it != req.urlParams.end())
Jason M. Bills16428a12018-11-02 12:42:29 -0700189 {
James Feist5a7e8772020-07-22 09:08:38 -0700190 std::string skipParam = it->value();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500191 char* ptr = nullptr;
James Feist5a7e8772020-07-22 09:08:38 -0700192 skip = std::strtoul(skipParam.c_str(), &ptr, 10);
193 if (skipParam.empty() || *ptr != '\0')
Jason M. Bills16428a12018-11-02 12:42:29 -0700194 {
195
196 messages::queryParameterValueTypeError(res, std::string(skipParam),
197 "$skip");
198 return false;
199 }
Jason M. Bills16428a12018-11-02 12:42:29 -0700200 }
201 return true;
202}
203
Ed Tanous271584a2019-07-09 16:24:22 -0700204static constexpr const uint64_t maxEntriesPerPage = 1000;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500205static bool getTopParam(crow::Response& res, const crow::Request& req,
206 uint64_t& top)
Jason M. Bills16428a12018-11-02 12:42:29 -0700207{
James Feist5a7e8772020-07-22 09:08:38 -0700208 boost::urls::url_view::params_type::iterator it =
209 req.urlParams.find("$top");
210 if (it != req.urlParams.end())
Jason M. Bills16428a12018-11-02 12:42:29 -0700211 {
James Feist5a7e8772020-07-22 09:08:38 -0700212 std::string topParam = it->value();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500213 char* ptr = nullptr;
James Feist5a7e8772020-07-22 09:08:38 -0700214 top = std::strtoul(topParam.c_str(), &ptr, 10);
215 if (topParam.empty() || *ptr != '\0')
Jason M. Bills16428a12018-11-02 12:42:29 -0700216 {
217 messages::queryParameterValueTypeError(res, std::string(topParam),
218 "$top");
219 return false;
220 }
Ed Tanous271584a2019-07-09 16:24:22 -0700221 if (top < 1U || top > maxEntriesPerPage)
Jason M. Bills16428a12018-11-02 12:42:29 -0700222 {
223
224 messages::queryParameterOutOfRange(
225 res, std::to_string(top), "$top",
226 "1-" + std::to_string(maxEntriesPerPage));
227 return false;
228 }
229 }
230 return true;
231}
232
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500233static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700234 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700235{
236 int ret = 0;
237 static uint64_t prevTs = 0;
238 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700239 if (firstEntry)
240 {
241 prevTs = 0;
242 }
243
Jason M. Bills16428a12018-11-02 12:42:29 -0700244 // Get the entry timestamp
245 uint64_t curTs = 0;
246 ret = sd_journal_get_realtime_usec(journal, &curTs);
247 if (ret < 0)
248 {
249 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
250 << strerror(-ret);
251 return false;
252 }
253 // If the timestamp isn't unique, increment the index
254 if (curTs == prevTs)
255 {
256 index++;
257 }
258 else
259 {
260 // Otherwise, reset it
261 index = 0;
262 }
263 // Save the timestamp
264 prevTs = curTs;
265
266 entryID = std::to_string(curTs);
267 if (index > 0)
268 {
269 entryID += "_" + std::to_string(index);
270 }
271 return true;
272}
273
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500274static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700275 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700276{
Ed Tanous271584a2019-07-09 16:24:22 -0700277 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700278 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700279 if (firstEntry)
280 {
281 prevTs = 0;
282 }
283
Jason M. Bills95820182019-04-22 16:25:34 -0700284 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700285 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700286 std::tm timeStruct = {};
287 std::istringstream entryStream(logEntry);
288 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
289 {
290 curTs = std::mktime(&timeStruct);
291 }
292 // If the timestamp isn't unique, increment the index
293 if (curTs == prevTs)
294 {
295 index++;
296 }
297 else
298 {
299 // Otherwise, reset it
300 index = 0;
301 }
302 // Save the timestamp
303 prevTs = curTs;
304
305 entryID = std::to_string(curTs);
306 if (index > 0)
307 {
308 entryID += "_" + std::to_string(index);
309 }
310 return true;
311}
312
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500313static bool getTimestampFromID(crow::Response& res, const std::string& entryID,
314 uint64_t& timestamp, uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700315{
316 if (entryID.empty())
317 {
318 return false;
319 }
320 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800321 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700322
Ed Tanous81ce6092020-12-17 16:54:55 +0000323 auto underscorePos = tsStr.find('_');
Jason M. Bills16428a12018-11-02 12:42:29 -0700324 if (underscorePos != tsStr.npos)
325 {
326 // Timestamp has an index
327 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800328 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700329 indexStr.remove_prefix(underscorePos + 1);
330 std::size_t pos;
331 try
332 {
Ed Tanous39e77502019-03-04 17:35:53 -0800333 index = std::stoul(std::string(indexStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700334 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500335 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700336 {
337 messages::resourceMissingAtURI(res, entryID);
338 return false;
339 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500340 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700341 {
342 messages::resourceMissingAtURI(res, entryID);
343 return false;
344 }
345 if (pos != indexStr.size())
346 {
347 messages::resourceMissingAtURI(res, entryID);
348 return false;
349 }
350 }
351 // Timestamp has no index
352 std::size_t pos;
353 try
354 {
Ed Tanous39e77502019-03-04 17:35:53 -0800355 timestamp = std::stoull(std::string(tsStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700356 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500357 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700358 {
359 messages::resourceMissingAtURI(res, entryID);
360 return false;
361 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500362 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700363 {
364 messages::resourceMissingAtURI(res, entryID);
365 return false;
366 }
367 if (pos != tsStr.size())
368 {
369 messages::resourceMissingAtURI(res, entryID);
370 return false;
371 }
372 return true;
373}
374
Jason M. Bills95820182019-04-22 16:25:34 -0700375static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500376 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700377{
378 static const std::filesystem::path redfishLogDir = "/var/log";
379 static const std::string redfishLogFilename = "redfish";
380
381 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500382 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700383 std::filesystem::directory_iterator(redfishLogDir))
384 {
385 // If we find a redfish log file, save the path
386 std::string filename = dirEnt.path().filename();
387 if (boost::starts_with(filename, redfishLogFilename))
388 {
389 redfishLogFiles.emplace_back(redfishLogDir / filename);
390 }
391 }
392 // As the log files rotate, they are appended with a ".#" that is higher for
393 // the older logs. Since we don't expect more than 10 log files, we
394 // can just sort the list to get them in order from newest to oldest
395 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
396
397 return !redfishLogFiles.empty();
398}
399
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500400inline void getDumpEntryCollection(std::shared_ptr<AsyncResp>& asyncResp,
401 const std::string& dumpType)
402{
403 std::string dumpPath;
404 if (dumpType == "BMC")
405 {
406 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
407 }
408 else if (dumpType == "System")
409 {
410 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
411 }
412 else
413 {
414 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
415 messages::internalError(asyncResp->res);
416 return;
417 }
418
419 crow::connections::systemBus->async_method_call(
420 [asyncResp, dumpPath, dumpType](const boost::system::error_code ec,
421 GetManagedObjectsType& resp) {
422 if (ec)
423 {
424 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
425 messages::internalError(asyncResp->res);
426 return;
427 }
428
429 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
430 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500431 std::string dumpEntryPath =
432 "/xyz/openbmc_project/dump/" +
433 std::string(boost::algorithm::to_lower_copy(dumpType)) +
434 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500435
436 for (auto& object : resp)
437 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500438 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500439 {
440 continue;
441 }
442 std::time_t timestamp;
443 uint64_t size = 0;
444 entriesArray.push_back({});
445 nlohmann::json& thisEntry = entriesArray.back();
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000446
447 std::string entryID = object.first.filename();
448 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500449 {
450 continue;
451 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500452
453 for (auto& interfaceMap : object.second)
454 {
455 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
456 {
457
458 for (auto& propertyMap : interfaceMap.second)
459 {
460 if (propertyMap.first == "Size")
461 {
462 auto sizePtr =
463 std::get_if<uint64_t>(&propertyMap.second);
464 if (sizePtr == nullptr)
465 {
466 messages::internalError(asyncResp->res);
467 break;
468 }
469 size = *sizePtr;
470 break;
471 }
472 }
473 }
474 else if (interfaceMap.first ==
475 "xyz.openbmc_project.Time.EpochTime")
476 {
477
478 for (auto& propertyMap : interfaceMap.second)
479 {
480 if (propertyMap.first == "Elapsed")
481 {
482 const uint64_t* usecsTimeStamp =
483 std::get_if<uint64_t>(&propertyMap.second);
484 if (usecsTimeStamp == nullptr)
485 {
486 messages::internalError(asyncResp->res);
487 break;
488 }
489 timestamp =
490 static_cast<std::time_t>(*usecsTimeStamp);
491 break;
492 }
493 }
494 }
495 }
496
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500497 thisEntry["@odata.type"] = "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500498 thisEntry["@odata.id"] = dumpPath + entryID;
499 thisEntry["Id"] = entryID;
500 thisEntry["EntryType"] = "Event";
501 thisEntry["Created"] = crow::utility::getDateTime(timestamp);
502 thisEntry["Name"] = dumpType + " Dump Entry";
503
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500504 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500505
506 if (dumpType == "BMC")
507 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500508 thisEntry["DiagnosticDataType"] = "Manager";
509 thisEntry["AdditionalDataURI"] =
510 "/redfish/v1/Managers/bmc/LogServices/Dump/"
511 "attachment/" +
512 entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500513 }
514 else if (dumpType == "System")
515 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500516 thisEntry["DiagnosticDataType"] = "OEM";
517 thisEntry["OEMDiagnosticDataType"] = "System";
518 thisEntry["AdditionalDataURI"] =
519 "/redfish/v1/Systems/system/LogServices/Dump/"
520 "attachment/" +
521 entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500522 }
523 }
524 asyncResp->res.jsonValue["Members@odata.count"] =
525 entriesArray.size();
526 },
527 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
528 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
529}
530
531inline void getDumpEntryById(std::shared_ptr<AsyncResp>& asyncResp,
532 const std::string& entryID,
533 const std::string& dumpType)
534{
535 std::string dumpPath;
536 if (dumpType == "BMC")
537 {
538 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
539 }
540 else if (dumpType == "System")
541 {
542 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
543 }
544 else
545 {
546 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
547 messages::internalError(asyncResp->res);
548 return;
549 }
550
551 crow::connections::systemBus->async_method_call(
552 [asyncResp, entryID, dumpPath, dumpType](
553 const boost::system::error_code ec, GetManagedObjectsType& resp) {
554 if (ec)
555 {
556 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
557 messages::internalError(asyncResp->res);
558 return;
559 }
560
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500561 bool foundDumpEntry = false;
562 std::string dumpEntryPath =
563 "/xyz/openbmc_project/dump/" +
564 std::string(boost::algorithm::to_lower_copy(dumpType)) +
565 "/entry/";
566
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500567 for (auto& objectPath : resp)
568 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500569 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500570 {
571 continue;
572 }
573
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500574 foundDumpEntry = true;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500575 std::time_t timestamp;
576 uint64_t size = 0;
577
578 for (auto& interfaceMap : objectPath.second)
579 {
580 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
581 {
582 for (auto& propertyMap : interfaceMap.second)
583 {
584 if (propertyMap.first == "Size")
585 {
586 auto sizePtr =
587 std::get_if<uint64_t>(&propertyMap.second);
588 if (sizePtr == nullptr)
589 {
590 messages::internalError(asyncResp->res);
591 break;
592 }
593 size = *sizePtr;
594 break;
595 }
596 }
597 }
598 else if (interfaceMap.first ==
599 "xyz.openbmc_project.Time.EpochTime")
600 {
601 for (auto& propertyMap : interfaceMap.second)
602 {
603 if (propertyMap.first == "Elapsed")
604 {
605 const uint64_t* usecsTimeStamp =
606 std::get_if<uint64_t>(&propertyMap.second);
607 if (usecsTimeStamp == nullptr)
608 {
609 messages::internalError(asyncResp->res);
610 break;
611 }
612 timestamp =
613 static_cast<std::time_t>(*usecsTimeStamp);
614 break;
615 }
616 }
617 }
618 }
619
620 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500621 "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500622 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
623 asyncResp->res.jsonValue["Id"] = entryID;
624 asyncResp->res.jsonValue["EntryType"] = "Event";
625 asyncResp->res.jsonValue["Created"] =
626 crow::utility::getDateTime(timestamp);
627 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
628
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500629 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500630
631 if (dumpType == "BMC")
632 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500633 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
634 asyncResp->res.jsonValue["AdditionalDataURI"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500635 "/redfish/v1/Managers/bmc/LogServices/Dump/"
636 "attachment/" +
637 entryID;
638 }
639 else if (dumpType == "System")
640 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500641 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
642 asyncResp->res.jsonValue["OEMDiagnosticDataType"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500643 "System";
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500644 asyncResp->res.jsonValue["AdditionalDataURI"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500645 "/redfish/v1/Systems/system/LogServices/Dump/"
646 "attachment/" +
647 entryID;
648 }
649 }
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500650 if (foundDumpEntry == false)
651 {
652 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
653 messages::internalError(asyncResp->res);
654 return;
655 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 },
657 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
658 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
659}
660
Stanley Chu98782562020-11-04 16:10:24 +0800661inline void deleteDumpEntry(const std::shared_ptr<AsyncResp>& asyncResp,
662 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500663 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500664{
George Liu3de8d8b2021-03-22 17:49:39 +0800665 auto respHandler = [asyncResp,
666 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500667 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
668 if (ec)
669 {
George Liu3de8d8b2021-03-22 17:49:39 +0800670 if (ec.value() == EBADR)
671 {
672 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
673 return;
674 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500675 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
676 << ec;
677 messages::internalError(asyncResp->res);
678 return;
679 }
680 };
681 crow::connections::systemBus->async_method_call(
682 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500683 "/xyz/openbmc_project/dump/" +
684 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
685 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500686 "xyz.openbmc_project.Object.Delete", "Delete");
687}
688
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500689inline void createDumpTaskCallback(const crow::Request& req,
Ed Tanousb5a76932020-09-29 16:16:58 -0700690 const std::shared_ptr<AsyncResp>& asyncResp,
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500691 const uint32_t& dumpId,
692 const std::string& dumpPath,
693 const std::string& dumpType)
694{
695 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500696 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500697 boost::system::error_code err, sdbusplus::message::message& m,
698 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000699 if (err)
700 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500701 BMCWEB_LOG_ERROR << "Error in creating a dump";
702 taskData->state = "Cancelled";
703 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000704 }
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500705 std::vector<std::pair<
706 std::string,
707 std::vector<std::pair<std::string, std::variant<std::string>>>>>
708 interfacesList;
709
710 sdbusplus::message::object_path objPath;
711
712 m.read(objPath, interfacesList);
713
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500714 if (objPath.str ==
715 "/xyz/openbmc_project/dump/" +
716 std::string(boost::algorithm::to_lower_copy(dumpType)) +
717 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500718 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500719 nlohmann::json retMessage = messages::success();
720 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500721
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500722 std::string headerLoc =
723 "Location: " + dumpPath + std::to_string(dumpId);
724 taskData->payload->httpHeaders.emplace_back(
725 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500726
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500727 taskData->state = "Completed";
728 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500729 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500730 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500731 },
732 "type='signal',interface='org.freedesktop.DBus."
733 "ObjectManager',"
734 "member='InterfacesAdded', "
735 "path='/xyz/openbmc_project/dump'");
736
737 task->startTimer(std::chrono::minutes(3));
738 task->populateResp(asyncResp->res);
739 task->payload.emplace(req);
740}
741
742inline void createDump(crow::Response& res, const crow::Request& req,
743 const std::string& dumpType)
744{
745 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
746
747 std::string dumpPath;
748 if (dumpType == "BMC")
749 {
750 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
751 }
752 else if (dumpType == "System")
753 {
754 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
755 }
756 else
757 {
758 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
759 messages::internalError(asyncResp->res);
760 return;
761 }
762
763 std::optional<std::string> diagnosticDataType;
764 std::optional<std::string> oemDiagnosticDataType;
765
766 if (!redfish::json_util::readJson(
767 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
768 "OEMDiagnosticDataType", oemDiagnosticDataType))
769 {
770 return;
771 }
772
773 if (dumpType == "System")
774 {
775 if (!oemDiagnosticDataType || !diagnosticDataType)
776 {
777 BMCWEB_LOG_ERROR << "CreateDump action parameter "
778 "'DiagnosticDataType'/"
779 "'OEMDiagnosticDataType' value not found!";
780 messages::actionParameterMissing(
781 asyncResp->res, "CollectDiagnosticData",
782 "DiagnosticDataType & OEMDiagnosticDataType");
783 return;
784 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700785 if ((*oemDiagnosticDataType != "System") ||
786 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500787 {
788 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
789 messages::invalidObject(asyncResp->res,
790 "System Dump creation parameters");
791 return;
792 }
793 }
794 else if (dumpType == "BMC")
795 {
796 if (!diagnosticDataType)
797 {
798 BMCWEB_LOG_ERROR << "CreateDump action parameter "
799 "'DiagnosticDataType' not found!";
800 messages::actionParameterMissing(
801 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
802 return;
803 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700804 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500805 {
806 BMCWEB_LOG_ERROR
807 << "Wrong parameter value passed for 'DiagnosticDataType'";
808 messages::invalidObject(asyncResp->res,
809 "BMC Dump creation parameters");
810 return;
811 }
812 }
813
814 crow::connections::systemBus->async_method_call(
815 [asyncResp, req, dumpPath, dumpType](const boost::system::error_code ec,
816 const uint32_t& dumpId) {
817 if (ec)
818 {
819 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
820 messages::internalError(asyncResp->res);
821 return;
822 }
823 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
824
825 createDumpTaskCallback(req, asyncResp, dumpId, dumpPath, dumpType);
826 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500827 "xyz.openbmc_project.Dump.Manager",
828 "/xyz/openbmc_project/dump/" +
829 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500830 "xyz.openbmc_project.Dump.Create", "CreateDump");
831}
832
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500833inline void clearDump(crow::Response& res, const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500834{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500835 std::string dumpTypeLowerCopy =
836 std::string(boost::algorithm::to_lower_copy(dumpType));
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500837 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
838 crow::connections::systemBus->async_method_call(
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500839 [asyncResp, dumpType](const boost::system::error_code ec,
840 const std::vector<std::string>& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500841 if (ec)
842 {
843 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
844 messages::internalError(asyncResp->res);
845 return;
846 }
847
848 for (const std::string& path : subTreePaths)
849 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000850 sdbusplus::message::object_path objPath(path);
851 std::string logID = objPath.filename();
852 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500853 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000854 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500855 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000856 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500857 }
858 },
859 "xyz.openbmc_project.ObjectMapper",
860 "/xyz/openbmc_project/object_mapper",
861 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500862 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
863 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
864 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500865}
866
Ed Tanous2c70f802020-09-28 14:29:23 -0700867static void parseCrashdumpParameters(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500868 const std::vector<std::pair<std::string, VariantType>>& params,
869 std::string& filename, std::string& timestamp, std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700870{
871 for (auto property : params)
872 {
873 if (property.first == "Timestamp")
874 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500875 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500876 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700877 if (value != nullptr)
878 {
879 timestamp = *value;
880 }
881 }
882 else if (property.first == "Filename")
883 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500884 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500885 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700886 if (value != nullptr)
887 {
888 filename = *value;
889 }
890 }
891 else if (property.first == "Log")
892 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500893 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500894 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700895 if (value != nullptr)
896 {
897 logfile = *value;
898 }
899 }
900 }
901}
902
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500903constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800904class SystemLogServiceCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -0700905{
906 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700907 SystemLogServiceCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800908 Node(app, "/redfish/v1/Systems/system/LogServices/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800909 {
910 entityPrivileges = {
911 {boost::beast::http::verb::get, {{"Login"}}},
912 {boost::beast::http::verb::head, {{"Login"}}},
913 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
914 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
915 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
916 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
917 }
918
919 private:
920 /**
921 * Functions triggers appropriate requests on DBus
922 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000923 void doGet(crow::Response& res, const crow::Request&,
924 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800925 {
926 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800927 // Collections don't include the static data added by SubRoute because
928 // it has a duplicate entry for members
929 asyncResp->res.jsonValue["@odata.type"] =
930 "#LogServiceCollection.LogServiceCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800931 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -0800932 "/redfish/v1/Systems/system/LogServices";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800933 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
934 asyncResp->res.jsonValue["Description"] =
935 "Collection of LogServices for this Computer System";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500936 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800937 logServiceArray = nlohmann::json::array();
Ed Tanous029573d2019-02-01 10:57:49 -0800938 logServiceArray.push_back(
939 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/EventLog"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500940#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
raviteja-bc9bb6862020-02-03 11:53:32 -0600941 logServiceArray.push_back(
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500942 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/Dump"}});
raviteja-bc9bb6862020-02-03 11:53:32 -0600943#endif
944
Jason M. Billsd53dd412019-02-12 17:16:22 -0800945#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
946 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -0500947 {{"@odata.id",
948 "/redfish/v1/Systems/system/LogServices/Crashdump"}});
Jason M. Billsd53dd412019-02-12 17:16:22 -0800949#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800950 asyncResp->res.jsonValue["Members@odata.count"] =
951 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800952
953 crow::connections::systemBus->async_method_call(
954 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500955 const std::vector<std::string>& subtreePath) {
ZhikuiRena3316fc2020-01-29 14:58:08 -0800956 if (ec)
957 {
958 BMCWEB_LOG_ERROR << ec;
959 return;
960 }
961
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500962 for (auto& pathStr : subtreePath)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800963 {
964 if (pathStr.find("PostCode") != std::string::npos)
965 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000966 nlohmann::json& logServiceArrayLocal =
ZhikuiRena3316fc2020-01-29 14:58:08 -0800967 asyncResp->res.jsonValue["Members"];
Ed Tanous23a21a12020-07-25 04:45:05 +0000968 logServiceArrayLocal.push_back(
ZhikuiRena3316fc2020-01-29 14:58:08 -0800969 {{"@odata.id", "/redfish/v1/Systems/system/"
970 "LogServices/PostCodes"}});
971 asyncResp->res.jsonValue["Members@odata.count"] =
Ed Tanous23a21a12020-07-25 04:45:05 +0000972 logServiceArrayLocal.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800973 return;
974 }
975 }
976 },
977 "xyz.openbmc_project.ObjectMapper",
978 "/xyz/openbmc_project/object_mapper",
979 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500980 std::array<const char*, 1>{postCodeIface});
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800981 }
982};
983
984class EventLogService : public Node
985{
986 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700987 EventLogService(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800988 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800989 {
990 entityPrivileges = {
991 {boost::beast::http::verb::get, {{"Login"}}},
992 {boost::beast::http::verb::head, {{"Login"}}},
993 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
994 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
995 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
996 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
997 }
998
999 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001000 void doGet(crow::Response& res, const crow::Request&,
1001 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001002 {
1003 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1004
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001005 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001006 "/redfish/v1/Systems/system/LogServices/EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001007 asyncResp->res.jsonValue["@odata.type"] =
1008 "#LogService.v1_1_0.LogService";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001009 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1010 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
Gunnar Mills73ec8302020-04-14 16:02:42 -05001011 asyncResp->res.jsonValue["Id"] = "EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001012 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
1013 asyncResp->res.jsonValue["Entries"] = {
1014 {"@odata.id",
Ed Tanous029573d2019-02-01 10:57:49 -08001015 "/redfish/v1/Systems/system/LogServices/EventLog/Entries"}};
Gunnar Millse7d6c8b2019-07-03 11:30:01 -05001016 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1017
1018 {"target", "/redfish/v1/Systems/system/LogServices/EventLog/"
1019 "Actions/LogService.ClearLog"}};
Jason M. Bills489640c2019-05-17 09:56:36 -07001020 }
1021};
1022
Tim Lee1f56a3a2019-10-09 10:17:57 +08001023class JournalEventLogClear : public Node
Jason M. Bills489640c2019-05-17 09:56:36 -07001024{
1025 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001026 JournalEventLogClear(App& app) :
Jason M. Bills489640c2019-05-17 09:56:36 -07001027 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
1028 "LogService.ClearLog/")
1029 {
1030 entityPrivileges = {
1031 {boost::beast::http::verb::get, {{"Login"}}},
1032 {boost::beast::http::verb::head, {{"Login"}}},
1033 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1034 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1035 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1036 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1037 }
1038
1039 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001040 void doPost(crow::Response& res, const crow::Request&,
1041 const std::vector<std::string>&) override
Jason M. Bills489640c2019-05-17 09:56:36 -07001042 {
1043 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1044
1045 // Clear the EventLog by deleting the log files
1046 std::vector<std::filesystem::path> redfishLogFiles;
1047 if (getRedfishLogFiles(redfishLogFiles))
1048 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001049 for (const std::filesystem::path& file : redfishLogFiles)
Jason M. Bills489640c2019-05-17 09:56:36 -07001050 {
1051 std::error_code ec;
1052 std::filesystem::remove(file, ec);
1053 }
1054 }
1055
1056 // Reload rsyslog so it knows to start new log files
1057 crow::connections::systemBus->async_method_call(
1058 [asyncResp](const boost::system::error_code ec) {
1059 if (ec)
1060 {
1061 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1062 messages::internalError(asyncResp->res);
1063 return;
1064 }
1065
1066 messages::success(asyncResp->res);
1067 },
1068 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1069 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1070 "replace");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001071 }
1072};
1073
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001074static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001075 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001076 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001077{
Jason M. Bills95820182019-04-22 16:25:34 -07001078 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001079 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001080 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001081 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001082 {
1083 return 1;
1084 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001085 std::string timestamp = logEntry.substr(0, space);
1086 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001087 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001088 if (entryStart == std::string::npos)
1089 {
1090 return 1;
1091 }
1092 std::string_view entry(logEntry);
1093 entry.remove_prefix(entryStart);
1094 // Use split to separate the entry into its fields
1095 std::vector<std::string> logEntryFields;
1096 boost::split(logEntryFields, entry, boost::is_any_of(","),
1097 boost::token_compress_on);
1098 // We need at least a MessageId to be valid
1099 if (logEntryFields.size() < 1)
1100 {
1101 return 1;
1102 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001103 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001104
Jason M. Bills4851d452019-03-28 11:27:48 -07001105 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001106 const message_registries::Message* message =
Jason M. Bills4851d452019-03-28 11:27:48 -07001107 message_registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001108
Jason M. Bills4851d452019-03-28 11:27:48 -07001109 std::string msg;
1110 std::string severity;
1111 if (message != nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001112 {
Jason M. Bills4851d452019-03-28 11:27:48 -07001113 msg = message->message;
1114 severity = message->severity;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001115 }
1116
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001117 // Get the MessageArgs from the log if there are any
1118 boost::beast::span<std::string> messageArgs;
1119 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001120 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001121 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001122 // If the first string is empty, assume there are no MessageArgs
1123 std::size_t messageArgsSize = 0;
1124 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001125 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001126 messageArgsSize = logEntryFields.size() - 1;
1127 }
1128
Ed Tanous23a21a12020-07-25 04:45:05 +00001129 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001130
1131 // Fill the MessageArgs into the Message
1132 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001133 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001134 {
1135 std::string argStr = "%" + std::to_string(++i);
1136 size_t argPos = msg.find(argStr);
1137 if (argPos != std::string::npos)
1138 {
1139 msg.replace(argPos, argStr.length(), messageArg);
1140 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001141 }
1142 }
1143
Jason M. Bills95820182019-04-22 16:25:34 -07001144 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1145 // format which matches the Redfish format except for the fractional seconds
1146 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001147 std::size_t dot = timestamp.find_first_of('.');
1148 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001149 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001150 {
Jason M. Bills95820182019-04-22 16:25:34 -07001151 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001152 }
1153
1154 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001155 logEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001156 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001157 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001158 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001159 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001160 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001161 {"Id", logEntryID},
1162 {"Message", std::move(msg)},
1163 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001164 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001165 {"EntryType", "Event"},
Jason M. Bills95820182019-04-22 16:25:34 -07001166 {"Severity", std::move(severity)},
1167 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001168 return 0;
1169}
1170
Anthony Wilson27062602019-04-22 02:10:09 -05001171class JournalEventLogEntryCollection : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001172{
1173 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001174 JournalEventLogEntryCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -08001175 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001176 {
1177 entityPrivileges = {
1178 {boost::beast::http::verb::get, {{"Login"}}},
1179 {boost::beast::http::verb::head, {{"Login"}}},
1180 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1181 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1182 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1183 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1184 }
1185
1186 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001187 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00001188 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001189 {
1190 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous271584a2019-07-09 16:24:22 -07001191 uint64_t skip = 0;
1192 uint64_t top = maxEntriesPerPage; // Show max entries by default
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001193 if (!getSkipParam(asyncResp->res, req, skip))
1194 {
1195 return;
1196 }
1197 if (!getTopParam(asyncResp->res, req, top))
1198 {
1199 return;
1200 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001201 // Collections don't include the static data added by SubRoute because
1202 // it has a duplicate entry for members
1203 asyncResp->res.jsonValue["@odata.type"] =
1204 "#LogEntryCollection.LogEntryCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001205 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001206 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001207 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1208 asyncResp->res.jsonValue["Description"] =
1209 "Collection of System Event Log Entries";
Andrew Geisslercb92c032018-08-17 07:56:14 -07001210
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001211 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001212 logEntryArray = nlohmann::json::array();
Jason M. Bills95820182019-04-22 16:25:34 -07001213 // Go through the log files and create a unique ID for each entry
1214 std::vector<std::filesystem::path> redfishLogFiles;
1215 getRedfishLogFiles(redfishLogFiles);
Ed Tanousb01bf292019-03-25 19:25:26 +00001216 uint64_t entryCount = 0;
Jason M. Billscd225da2019-05-08 15:31:57 -07001217 std::string logEntry;
Jason M. Bills95820182019-04-22 16:25:34 -07001218
1219 // Oldest logs are in the last file, so start there and loop backwards
Jason M. Billscd225da2019-05-08 15:31:57 -07001220 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1221 it++)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001222 {
Jason M. Billscd225da2019-05-08 15:31:57 -07001223 std::ifstream logStream(*it);
Jason M. Bills95820182019-04-22 16:25:34 -07001224 if (!logStream.is_open())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001225 {
1226 continue;
1227 }
1228
Jason M. Billse85d6b12019-07-29 17:01:15 -07001229 // Reset the unique ID on the first entry
1230 bool firstEntry = true;
Jason M. Bills95820182019-04-22 16:25:34 -07001231 while (std::getline(logStream, logEntry))
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001232 {
Jason M. Bills95820182019-04-22 16:25:34 -07001233 entryCount++;
1234 // Handle paging using skip (number of entries to skip from the
1235 // start) and top (number of entries to display)
1236 if (entryCount <= skip || entryCount > skip + top)
1237 {
1238 continue;
1239 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001240
Jason M. Bills95820182019-04-22 16:25:34 -07001241 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07001242 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills95820182019-04-22 16:25:34 -07001243 {
1244 continue;
1245 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001246
Jason M. Billse85d6b12019-07-29 17:01:15 -07001247 if (firstEntry)
1248 {
1249 firstEntry = false;
1250 }
1251
Jason M. Bills95820182019-04-22 16:25:34 -07001252 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001253 nlohmann::json& bmcLogEntry = logEntryArray.back();
Jason M. Bills95820182019-04-22 16:25:34 -07001254 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1255 {
1256 messages::internalError(asyncResp->res);
1257 return;
1258 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001259 }
1260 }
1261 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1262 if (skip + top < entryCount)
1263 {
1264 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Bills95820182019-04-22 16:25:34 -07001265 "/redfish/v1/Systems/system/LogServices/EventLog/"
1266 "Entries?$skip=" +
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001267 std::to_string(skip + top);
1268 }
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001269 }
1270};
1271
Jason M. Bills897967d2019-07-29 17:05:30 -07001272class JournalEventLogEntry : public Node
1273{
1274 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001275 JournalEventLogEntry(App& app) :
Jason M. Bills897967d2019-07-29 17:05:30 -07001276 Node(app,
1277 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1278 std::string())
1279 {
1280 entityPrivileges = {
1281 {boost::beast::http::verb::get, {{"Login"}}},
1282 {boost::beast::http::verb::head, {{"Login"}}},
1283 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1284 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1285 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1286 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1287 }
1288
1289 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001290 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001291 const std::vector<std::string>& params) override
Jason M. Bills897967d2019-07-29 17:05:30 -07001292 {
1293 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1294 if (params.size() != 1)
1295 {
1296 messages::internalError(asyncResp->res);
1297 return;
1298 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001299 const std::string& targetID = params[0];
Jason M. Bills897967d2019-07-29 17:05:30 -07001300
1301 // Go through the log files and check the unique ID for each entry to
1302 // find the target entry
1303 std::vector<std::filesystem::path> redfishLogFiles;
1304 getRedfishLogFiles(redfishLogFiles);
1305 std::string logEntry;
1306
1307 // Oldest logs are in the last file, so start there and loop backwards
1308 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1309 it++)
1310 {
1311 std::ifstream logStream(*it);
1312 if (!logStream.is_open())
1313 {
1314 continue;
1315 }
1316
1317 // Reset the unique ID on the first entry
1318 bool firstEntry = true;
1319 while (std::getline(logStream, logEntry))
1320 {
1321 std::string idStr;
1322 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1323 {
1324 continue;
1325 }
1326
1327 if (firstEntry)
1328 {
1329 firstEntry = false;
1330 }
1331
1332 if (idStr == targetID)
1333 {
1334 if (fillEventLogEntryJson(idStr, logEntry,
1335 asyncResp->res.jsonValue) != 0)
1336 {
1337 messages::internalError(asyncResp->res);
1338 return;
1339 }
1340 return;
1341 }
1342 }
1343 }
1344 // Requested ID was not found
1345 messages::resourceMissingAtURI(asyncResp->res, targetID);
1346 }
1347};
1348
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001349class DBusEventLogEntryCollection : public Node
1350{
1351 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001352 DBusEventLogEntryCollection(App& app) :
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001353 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
1354 {
1355 entityPrivileges = {
1356 {boost::beast::http::verb::get, {{"Login"}}},
1357 {boost::beast::http::verb::head, {{"Login"}}},
1358 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1359 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1360 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1361 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1362 }
1363
1364 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001365 void doGet(crow::Response& res, const crow::Request&,
1366 const std::vector<std::string>&) override
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001367 {
1368 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1369
1370 // Collections don't include the static data added by SubRoute because
1371 // it has a duplicate entry for members
1372 asyncResp->res.jsonValue["@odata.type"] =
1373 "#LogEntryCollection.LogEntryCollection";
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001374 asyncResp->res.jsonValue["@odata.id"] =
1375 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1376 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1377 asyncResp->res.jsonValue["Description"] =
1378 "Collection of System Event Log Entries";
1379
Andrew Geisslercb92c032018-08-17 07:56:14 -07001380 // DBus implementation of EventLog/Entries
1381 // Make call to Logging Service to find all log entry objects
1382 crow::connections::systemBus->async_method_call(
1383 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001384 GetManagedObjectsType& resp) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001385 if (ec)
1386 {
1387 // TODO Handle for specific error code
1388 BMCWEB_LOG_ERROR
1389 << "getLogEntriesIfaceData resp_handler got error "
1390 << ec;
1391 messages::internalError(asyncResp->res);
1392 return;
1393 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001394 nlohmann::json& entriesArray =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001395 asyncResp->res.jsonValue["Members"];
1396 entriesArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001397 for (auto& objectPath : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001398 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001399 for (auto& interfaceMap : objectPath.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001400 {
1401 if (interfaceMap.first !=
1402 "xyz.openbmc_project.Logging.Entry")
1403 {
1404 BMCWEB_LOG_DEBUG << "Bailing early on "
1405 << interfaceMap.first;
1406 continue;
1407 }
1408 entriesArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001409 nlohmann::json& thisEntry = entriesArray.back();
1410 uint32_t* id = nullptr;
Ed Tanous66664f22019-10-11 13:05:49 -07001411 std::time_t timestamp{};
George Liud139c232020-08-18 18:48:57 +08001412 std::time_t updateTimestamp{};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001413 std::string* severity = nullptr;
1414 std::string* message = nullptr;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001415 bool resolved = false;
George Liud139c232020-08-18 18:48:57 +08001416
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001417 for (auto& propertyMap : interfaceMap.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001418 {
1419 if (propertyMap.first == "Id")
1420 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -05001421 id = std::get_if<uint32_t>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001422 }
1423 else if (propertyMap.first == "Timestamp")
1424 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001425 const uint64_t* millisTimeStamp =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001426 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001427 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001428 {
1429 timestamp = crow::utility::getTimestamp(
1430 *millisTimeStamp);
1431 }
George Liud139c232020-08-18 18:48:57 +08001432 }
1433 else if (propertyMap.first == "UpdateTimestamp")
1434 {
1435 const uint64_t* millisTimeStamp =
1436 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001437 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001438 {
1439 updateTimestamp =
1440 crow::utility::getTimestamp(
1441 *millisTimeStamp);
1442 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001443 }
1444 else if (propertyMap.first == "Severity")
1445 {
1446 severity = std::get_if<std::string>(
1447 &propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001448 }
1449 else if (propertyMap.first == "Message")
1450 {
1451 message = std::get_if<std::string>(
1452 &propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001453 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001454 else if (propertyMap.first == "Resolved")
1455 {
1456 bool* resolveptr =
1457 std::get_if<bool>(&propertyMap.second);
1458 if (resolveptr == nullptr)
1459 {
1460 messages::internalError(asyncResp->res);
1461 return;
1462 }
1463 resolved = *resolveptr;
1464 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001465 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001466 if (id == nullptr || message == nullptr ||
1467 severity == nullptr)
1468 {
1469 messages::internalError(asyncResp->res);
1470 return;
1471 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001472 thisEntry = {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001473 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001474 {"@odata.id",
1475 "/redfish/v1/Systems/system/LogServices/EventLog/"
1476 "Entries/" +
1477 std::to_string(*id)},
Anthony Wilson27062602019-04-22 02:10:09 -05001478 {"Name", "System Event Log Entry"},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001479 {"Id", std::to_string(*id)},
1480 {"Message", *message},
Xiaochao Ma75710de2021-01-21 17:56:02 +08001481 {"Resolved", resolved},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001482 {"EntryType", "Event"},
1483 {"Severity",
1484 translateSeverityDbusToRedfish(*severity)},
George Liud139c232020-08-18 18:48:57 +08001485 {"Created", crow::utility::getDateTime(timestamp)},
1486 {"Modified",
1487 crow::utility::getDateTime(updateTimestamp)}};
Andrew Geisslercb92c032018-08-17 07:56:14 -07001488 }
1489 }
1490 std::sort(entriesArray.begin(), entriesArray.end(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001491 [](const nlohmann::json& left,
1492 const nlohmann::json& right) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001493 return (left["Id"] <= right["Id"]);
1494 });
1495 asyncResp->res.jsonValue["Members@odata.count"] =
1496 entriesArray.size();
1497 },
1498 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1499 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001500 }
1501};
1502
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001503class DBusEventLogEntry : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001504{
1505 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001506 DBusEventLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001507 Node(app,
Ed Tanous029573d2019-02-01 10:57:49 -08001508 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1509 std::string())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001510 {
1511 entityPrivileges = {
1512 {boost::beast::http::verb::get, {{"Login"}}},
1513 {boost::beast::http::verb::head, {{"Login"}}},
1514 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1515 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1516 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1517 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1518 }
1519
1520 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001521 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001522 const std::vector<std::string>& params) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001523 {
1524 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous029573d2019-02-01 10:57:49 -08001525 if (params.size() != 1)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001526 {
1527 messages::internalError(asyncResp->res);
1528 return;
1529 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001530 std::string entryID = params[0];
1531 dbus::utility::escapePathForDbus(entryID);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001532
Andrew Geisslercb92c032018-08-17 07:56:14 -07001533 // DBus implementation of EventLog/Entries
1534 // Make call to Logging Service to find all log entry objects
1535 crow::connections::systemBus->async_method_call(
1536 [asyncResp, entryID](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001537 GetManagedPropertyType& resp) {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001538 if (ec.value() == EBADR)
1539 {
1540 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1541 entryID);
1542 return;
1543 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001544 if (ec)
1545 {
1546 BMCWEB_LOG_ERROR
1547 << "EventLogEntry (DBus) resp_handler got error " << ec;
1548 messages::internalError(asyncResp->res);
1549 return;
1550 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001551 uint32_t* id = nullptr;
Ed Tanous66664f22019-10-11 13:05:49 -07001552 std::time_t timestamp{};
George Liud139c232020-08-18 18:48:57 +08001553 std::time_t updateTimestamp{};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001554 std::string* severity = nullptr;
1555 std::string* message = nullptr;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001556 bool resolved = false;
George Liud139c232020-08-18 18:48:57 +08001557
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001558 for (auto& propertyMap : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001559 {
1560 if (propertyMap.first == "Id")
1561 {
1562 id = std::get_if<uint32_t>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001563 }
1564 else if (propertyMap.first == "Timestamp")
1565 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001566 const uint64_t* millisTimeStamp =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001567 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001568 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001569 {
1570 timestamp =
1571 crow::utility::getTimestamp(*millisTimeStamp);
1572 }
George Liud139c232020-08-18 18:48:57 +08001573 }
1574 else if (propertyMap.first == "UpdateTimestamp")
1575 {
1576 const uint64_t* millisTimeStamp =
1577 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001578 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001579 {
1580 updateTimestamp =
1581 crow::utility::getTimestamp(*millisTimeStamp);
1582 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001583 }
1584 else if (propertyMap.first == "Severity")
1585 {
1586 severity =
1587 std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001588 }
1589 else if (propertyMap.first == "Message")
1590 {
1591 message = std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001592 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001593 else if (propertyMap.first == "Resolved")
1594 {
1595 bool* resolveptr =
1596 std::get_if<bool>(&propertyMap.second);
1597 if (resolveptr == nullptr)
1598 {
1599 messages::internalError(asyncResp->res);
1600 return;
1601 }
1602 resolved = *resolveptr;
1603 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001604 }
Ed Tanous271584a2019-07-09 16:24:22 -07001605 if (id == nullptr || message == nullptr || severity == nullptr)
1606 {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001607 messages::internalError(asyncResp->res);
Ed Tanous271584a2019-07-09 16:24:22 -07001608 return;
1609 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001610 asyncResp->res.jsonValue = {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001611 {"@odata.type", "#LogEntry.v1_8_0.LogEntry"},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001612 {"@odata.id",
1613 "/redfish/v1/Systems/system/LogServices/EventLog/"
1614 "Entries/" +
1615 std::to_string(*id)},
Anthony Wilson27062602019-04-22 02:10:09 -05001616 {"Name", "System Event Log Entry"},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001617 {"Id", std::to_string(*id)},
1618 {"Message", *message},
Xiaochao Ma75710de2021-01-21 17:56:02 +08001619 {"Resolved", resolved},
Andrew Geisslercb92c032018-08-17 07:56:14 -07001620 {"EntryType", "Event"},
1621 {"Severity", translateSeverityDbusToRedfish(*severity)},
George Liud139c232020-08-18 18:48:57 +08001622 {"Created", crow::utility::getDateTime(timestamp)},
1623 {"Modified", crow::utility::getDateTime(updateTimestamp)}};
Andrew Geisslercb92c032018-08-17 07:56:14 -07001624 },
1625 "xyz.openbmc_project.Logging",
1626 "/xyz/openbmc_project/logging/entry/" + entryID,
1627 "org.freedesktop.DBus.Properties", "GetAll",
1628 "xyz.openbmc_project.Logging.Entry");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001629 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001630
Xiaochao Ma75710de2021-01-21 17:56:02 +08001631 void doPatch(crow::Response& res, const crow::Request& req,
1632 const std::vector<std::string>& params) override
1633 {
1634 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1635
1636 if (params.size() != 1)
1637 {
1638 messages::internalError(asyncResp->res);
1639 return;
1640 }
1641 std::string entryId = params[0];
1642
1643 std::optional<bool> resolved;
1644
1645 if (!json_util::readJson(req, res, "Resolved", resolved))
1646 {
1647 return;
1648 }
1649
1650 if (resolved)
1651 {
1652 BMCWEB_LOG_DEBUG << "Set Resolved";
1653
1654 crow::connections::systemBus->async_method_call(
1655 [asyncResp, resolved,
1656 entryId](const boost::system::error_code ec) {
1657 if (ec)
1658 {
1659 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1660 messages::internalError(asyncResp->res);
1661 return;
1662 }
1663 },
1664 "xyz.openbmc_project.Logging",
1665 "/xyz/openbmc_project/logging/entry/" + entryId,
1666 "org.freedesktop.DBus.Properties", "Set",
1667 "xyz.openbmc_project.Logging.Entry", "Resolved",
1668 std::variant<bool>(*resolved));
1669 }
1670 }
1671
Ed Tanouscb13a392020-07-25 19:02:03 +00001672 void doDelete(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001673 const std::vector<std::string>& params) override
Chicago Duan336e96c2019-07-15 14:22:08 +08001674 {
1675
1676 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1677
1678 auto asyncResp = std::make_shared<AsyncResp>(res);
1679
1680 if (params.size() != 1)
1681 {
1682 messages::internalError(asyncResp->res);
1683 return;
1684 }
1685 std::string entryID = params[0];
1686
1687 dbus::utility::escapePathForDbus(entryID);
1688
1689 // Process response from Logging service.
George Liu3de8d8b2021-03-22 17:49:39 +08001690 auto respHandler = [asyncResp,
1691 entryID](const boost::system::error_code ec) {
Chicago Duan336e96c2019-07-15 14:22:08 +08001692 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1693 if (ec)
1694 {
George Liu3de8d8b2021-03-22 17:49:39 +08001695 if (ec.value() == EBADR)
1696 {
1697 messages::resourceNotFound(asyncResp->res, "LogEntry",
1698 entryID);
1699 return;
1700 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001701 // TODO Handle for specific error code
1702 BMCWEB_LOG_ERROR
1703 << "EventLogEntry (DBus) doDelete respHandler got error "
1704 << ec;
1705 asyncResp->res.result(
1706 boost::beast::http::status::internal_server_error);
1707 return;
1708 }
1709
1710 asyncResp->res.result(boost::beast::http::status::ok);
1711 };
1712
1713 // Make call to Logging service to request Delete Log
1714 crow::connections::systemBus->async_method_call(
1715 respHandler, "xyz.openbmc_project.Logging",
1716 "/xyz/openbmc_project/logging/entry/" + entryID,
1717 "xyz.openbmc_project.Object.Delete", "Delete");
1718 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001719};
1720
1721class BMCLogServiceCollection : public Node
1722{
1723 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001724 BMCLogServiceCollection(App& app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -07001725 Node(app, "/redfish/v1/Managers/bmc/LogServices/")
Ed Tanous1da66f72018-07-27 16:13:37 -07001726 {
Ed Tanous1da66f72018-07-27 16:13:37 -07001727 entityPrivileges = {
Jason M. Billse1f26342018-07-18 12:12:00 -07001728 {boost::beast::http::verb::get, {{"Login"}}},
1729 {boost::beast::http::verb::head, {{"Login"}}},
1730 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1731 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1732 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1733 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07001734 }
1735
1736 private:
1737 /**
1738 * Functions triggers appropriate requests on DBus
1739 */
Ed Tanouscb13a392020-07-25 19:02:03 +00001740 void doGet(crow::Response& res, const crow::Request&,
1741 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07001742 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001743 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07001744 // Collections don't include the static data added by SubRoute because
1745 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07001746 asyncResp->res.jsonValue["@odata.type"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001747 "#LogServiceCollection.LogServiceCollection";
Jason M. Billse1f26342018-07-18 12:12:00 -07001748 asyncResp->res.jsonValue["@odata.id"] =
1749 "/redfish/v1/Managers/bmc/LogServices";
1750 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
1751 asyncResp->res.jsonValue["Description"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001752 "Collection of LogServices for this Manager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001753 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001754 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001755#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
1756 logServiceArray.push_back(
1757 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
1758#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001759#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
1760 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001761 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001762#endif
Jason M. Billse1f26342018-07-18 12:12:00 -07001763 asyncResp->res.jsonValue["Members@odata.count"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001764 logServiceArray.size();
Ed Tanous1da66f72018-07-27 16:13:37 -07001765 }
1766};
1767
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001768class BMCJournalLogService : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07001769{
1770 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001771 BMCJournalLogService(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001772 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Jason M. Billse1f26342018-07-18 12:12:00 -07001773 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001774 entityPrivileges = {
1775 {boost::beast::http::verb::get, {{"Login"}}},
1776 {boost::beast::http::verb::head, {{"Login"}}},
1777 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1778 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1779 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1780 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1781 }
1782
1783 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001784 void doGet(crow::Response& res, const crow::Request&,
1785 const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07001786 {
1787 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Billse1f26342018-07-18 12:12:00 -07001788 asyncResp->res.jsonValue["@odata.type"] =
1789 "#LogService.v1_1_0.LogService";
Ed Tanous0f74e642018-11-12 15:17:05 -08001790 asyncResp->res.jsonValue["@odata.id"] =
1791 "/redfish/v1/Managers/bmc/LogServices/Journal";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001792 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
1793 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
1794 asyncResp->res.jsonValue["Id"] = "BMC Journal";
Jason M. Billse1f26342018-07-18 12:12:00 -07001795 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Jason M. Billscd50aa42019-02-12 17:09:02 -08001796 asyncResp->res.jsonValue["Entries"] = {
1797 {"@odata.id",
Ed Tanous086be232019-05-23 11:47:09 -07001798 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07001799 }
1800};
1801
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001802static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
1803 sd_journal* journal,
1804 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07001805{
1806 // Get the Log Entry contents
1807 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07001808
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001809 std::string message;
1810 std::string_view syslogID;
1811 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
1812 if (ret < 0)
1813 {
1814 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
1815 << strerror(-ret);
1816 }
1817 if (!syslogID.empty())
1818 {
1819 message += std::string(syslogID) + ": ";
1820 }
1821
Ed Tanous39e77502019-03-04 17:35:53 -08001822 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07001823 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001824 if (ret < 0)
1825 {
1826 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
1827 return 1;
1828 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001829 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001830
1831 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07001832 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07001833 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07001834 if (ret < 0)
1835 {
1836 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07001837 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001838
1839 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07001840 std::string entryTimeStr;
1841 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07001842 {
Jason M. Bills16428a12018-11-02 12:42:29 -07001843 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07001844 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001845
1846 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001847 bmcJournalLogEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001848 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001849 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
1850 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07001851 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001852 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001853 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07001854 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06001855 {"Severity", severity <= 2 ? "Critical"
1856 : severity <= 4 ? "Warning"
1857 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07001858 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07001859 {"Created", std::move(entryTimeStr)}};
1860 return 0;
1861}
1862
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001863class BMCJournalLogEntryCollection : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07001864{
1865 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001866 BMCJournalLogEntryCollection(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001867 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Jason M. Billse1f26342018-07-18 12:12:00 -07001868 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001869 entityPrivileges = {
1870 {boost::beast::http::verb::get, {{"Login"}}},
1871 {boost::beast::http::verb::head, {{"Login"}}},
1872 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1873 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1874 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1875 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1876 }
1877
1878 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001879 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00001880 const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07001881 {
1882 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001883 static constexpr const long maxEntriesPerPage = 1000;
Ed Tanous271584a2019-07-09 16:24:22 -07001884 uint64_t skip = 0;
1885 uint64_t top = maxEntriesPerPage; // Show max entries by default
Jason M. Bills16428a12018-11-02 12:42:29 -07001886 if (!getSkipParam(asyncResp->res, req, skip))
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001887 {
Jason M. Bills16428a12018-11-02 12:42:29 -07001888 return;
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001889 }
Jason M. Bills16428a12018-11-02 12:42:29 -07001890 if (!getTopParam(asyncResp->res, req, top))
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001891 {
Jason M. Bills16428a12018-11-02 12:42:29 -07001892 return;
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001893 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001894 // Collections don't include the static data added by SubRoute because
1895 // it has a duplicate entry for members
1896 asyncResp->res.jsonValue["@odata.type"] =
1897 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08001898 asyncResp->res.jsonValue["@odata.id"] =
1899 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07001900 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001901 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07001902 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
1903 asyncResp->res.jsonValue["Description"] =
1904 "Collection of BMC Journal Entries";
Ed Tanous0f74e642018-11-12 15:17:05 -08001905 asyncResp->res.jsonValue["@odata.id"] =
1906 "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001907 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07001908 logEntryArray = nlohmann::json::array();
1909
1910 // Go through the journal and use the timestamp to create a unique ID
1911 // for each entry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001912 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07001913 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
1914 if (ret < 0)
1915 {
1916 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07001917 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07001918 return;
1919 }
1920 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
1921 journalTmp, sd_journal_close);
1922 journalTmp = nullptr;
Ed Tanousb01bf292019-03-25 19:25:26 +00001923 uint64_t entryCount = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -07001924 // Reset the unique ID on the first entry
1925 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07001926 SD_JOURNAL_FOREACH(journal.get())
1927 {
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001928 entryCount++;
1929 // Handle paging using skip (number of entries to skip from the
1930 // start) and top (number of entries to display)
1931 if (entryCount <= skip || entryCount > skip + top)
1932 {
1933 continue;
1934 }
1935
Jason M. Bills16428a12018-11-02 12:42:29 -07001936 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07001937 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
Jason M. Billse1f26342018-07-18 12:12:00 -07001938 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001939 continue;
1940 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001941
Jason M. Billse85d6b12019-07-29 17:01:15 -07001942 if (firstEntry)
1943 {
1944 firstEntry = false;
1945 }
1946
Jason M. Billse1f26342018-07-18 12:12:00 -07001947 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001948 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001949 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
1950 bmcJournalLogEntry) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07001951 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001952 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07001953 return;
1954 }
1955 }
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001956 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1957 if (skip + top < entryCount)
1958 {
1959 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001960 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Jason M. Bills193ad2f2018-09-26 15:08:52 -07001961 std::to_string(skip + top);
1962 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001963 }
1964};
1965
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001966class BMCJournalLogEntry : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07001967{
1968 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001969 BMCJournalLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001970 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/",
Jason M. Billse1f26342018-07-18 12:12:00 -07001971 std::string())
1972 {
1973 entityPrivileges = {
1974 {boost::beast::http::verb::get, {{"Login"}}},
1975 {boost::beast::http::verb::head, {{"Login"}}},
1976 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1977 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1978 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1979 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1980 }
1981
1982 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001983 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001984 const std::vector<std::string>& params) override
Jason M. Billse1f26342018-07-18 12:12:00 -07001985 {
1986 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1987 if (params.size() != 1)
1988 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07001989 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07001990 return;
1991 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001992 const std::string& entryID = params[0];
Jason M. Billse1f26342018-07-18 12:12:00 -07001993 // Convert the unique ID back to a timestamp to find the entry
Jason M. Billse1f26342018-07-18 12:12:00 -07001994 uint64_t ts = 0;
Ed Tanous271584a2019-07-09 16:24:22 -07001995 uint64_t index = 0;
Jason M. Bills16428a12018-11-02 12:42:29 -07001996 if (!getTimestampFromID(asyncResp->res, entryID, ts, index))
Jason M. Billse1f26342018-07-18 12:12:00 -07001997 {
Jason M. Bills16428a12018-11-02 12:42:29 -07001998 return;
Jason M. Billse1f26342018-07-18 12:12:00 -07001999 }
2000
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002001 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07002002 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2003 if (ret < 0)
2004 {
2005 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07002006 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002007 return;
2008 }
2009 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2010 journalTmp, sd_journal_close);
2011 journalTmp = nullptr;
2012 // Go to the timestamp in the log and move to the entry at the index
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002013 // tracking the unique ID
2014 std::string idStr;
2015 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07002016 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
Manojkiran Eda2056b6d2020-05-28 08:57:36 +05302017 if (ret < 0)
2018 {
2019 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2020 << strerror(-ret);
2021 messages::internalError(asyncResp->res);
2022 return;
2023 }
Ed Tanous271584a2019-07-09 16:24:22 -07002024 for (uint64_t i = 0; i <= index; i++)
Jason M. Billse1f26342018-07-18 12:12:00 -07002025 {
2026 sd_journal_next(journal.get());
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002027 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2028 {
2029 messages::internalError(asyncResp->res);
2030 return;
2031 }
2032 if (firstEntry)
2033 {
2034 firstEntry = false;
2035 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002036 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002037 // Confirm that the entry ID matches what was requested
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002038 if (idStr != entryID)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002039 {
2040 messages::resourceMissingAtURI(asyncResp->res, entryID);
2041 return;
2042 }
2043
2044 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2045 asyncResp->res.jsonValue) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07002046 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002047 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002048 return;
2049 }
2050 }
2051};
2052
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002053class BMCDumpService : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002054{
2055 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002056 BMCDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002057 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002058 {
2059 entityPrivileges = {
2060 {boost::beast::http::verb::get, {{"Login"}}},
2061 {boost::beast::http::verb::head, {{"Login"}}},
2062 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2063 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2064 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2065 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2066 }
2067
2068 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002069 void doGet(crow::Response& res, const crow::Request&,
2070 const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002071 {
2072 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2073
2074 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002075 "/redfish/v1/Managers/bmc/LogServices/Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002076 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002077 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002078 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2079 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2080 asyncResp->res.jsonValue["Id"] = "Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002081 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
raviteja-bc9bb6862020-02-03 11:53:32 -06002082 asyncResp->res.jsonValue["Entries"] = {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002083 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"}};
2084 asyncResp->res.jsonValue["Actions"] = {
2085 {"#LogService.ClearLog",
2086 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2087 "Actions/LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002088 {"#LogService.CollectDiagnosticData",
2089 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2090 "Actions/LogService.CollectDiagnosticData"}}}};
raviteja-bc9bb6862020-02-03 11:53:32 -06002091 }
2092};
2093
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002094class BMCDumpEntryCollection : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002095{
2096 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002097 BMCDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002098 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002099 {
2100 entityPrivileges = {
2101 {boost::beast::http::verb::get, {{"Login"}}},
2102 {boost::beast::http::verb::head, {{"Login"}}},
2103 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2104 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2105 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2106 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2107 }
2108
2109 private:
2110 /**
2111 * Functions triggers appropriate requests on DBus
2112 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002113 void doGet(crow::Response& res, const crow::Request&,
2114 const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002115 {
2116 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2117
2118 asyncResp->res.jsonValue["@odata.type"] =
2119 "#LogEntryCollection.LogEntryCollection";
2120 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002121 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2122 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002123 asyncResp->res.jsonValue["Description"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002124 "Collection of BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002125
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002126 getDumpEntryCollection(asyncResp, "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002127 }
2128};
2129
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002130class BMCDumpEntry : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002131{
2132 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002133 BMCDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002134 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/",
raviteja-bc9bb6862020-02-03 11:53:32 -06002135 std::string())
2136 {
2137 entityPrivileges = {
2138 {boost::beast::http::verb::get, {{"Login"}}},
2139 {boost::beast::http::verb::head, {{"Login"}}},
2140 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2141 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2142 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2143 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2144 }
2145
2146 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002147 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002148 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002149 {
2150 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2151 if (params.size() != 1)
2152 {
2153 messages::internalError(asyncResp->res);
2154 return;
2155 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002156 getDumpEntryById(asyncResp, params[0], "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002157 }
2158
Ed Tanouscb13a392020-07-25 19:02:03 +00002159 void doDelete(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002160 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002161 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002162 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
raviteja-bc9bb6862020-02-03 11:53:32 -06002163 if (params.size() != 1)
2164 {
2165 messages::internalError(asyncResp->res);
2166 return;
2167 }
Stanley Chu98782562020-11-04 16:10:24 +08002168 deleteDumpEntry(asyncResp, params[0], "bmc");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002169 }
2170};
raviteja-bc9bb6862020-02-03 11:53:32 -06002171
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002172class BMCDumpCreate : public Node
2173{
2174 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002175 BMCDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002176 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002177 "Actions/"
2178 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002179 {
2180 entityPrivileges = {
2181 {boost::beast::http::verb::get, {{"Login"}}},
2182 {boost::beast::http::verb::head, {{"Login"}}},
2183 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2184 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2185 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2186 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2187 }
2188
2189 private:
2190 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002191 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002192 {
2193 createDump(res, req, "BMC");
2194 }
2195};
2196
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002197class BMCDumpClear : public Node
2198{
2199 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002200 BMCDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002201 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
2202 "Actions/"
2203 "LogService.ClearLog/")
2204 {
2205 entityPrivileges = {
2206 {boost::beast::http::verb::get, {{"Login"}}},
2207 {boost::beast::http::verb::head, {{"Login"}}},
2208 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2209 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2210 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2211 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2212 }
2213
2214 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002215 void doPost(crow::Response& res, const crow::Request&,
2216 const std::vector<std::string>&) override
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002217 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -05002218 clearDump(res, "BMC");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002219 }
2220};
2221
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002222class SystemDumpService : public Node
2223{
2224 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002225 SystemDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002226 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/")
2227 {
2228 entityPrivileges = {
2229 {boost::beast::http::verb::get, {{"Login"}}},
2230 {boost::beast::http::verb::head, {{"Login"}}},
2231 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2232 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2233 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2234 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2235 }
raviteja-bc9bb6862020-02-03 11:53:32 -06002236
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002237 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002238 void doGet(crow::Response& res, const crow::Request&,
2239 const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002240 {
2241 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
raviteja-bc9bb6862020-02-03 11:53:32 -06002242
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002243 asyncResp->res.jsonValue["@odata.id"] =
2244 "/redfish/v1/Systems/system/LogServices/Dump";
2245 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002246 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002247 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2248 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2249 asyncResp->res.jsonValue["Id"] = "Dump";
2250 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2251 asyncResp->res.jsonValue["Entries"] = {
2252 {"@odata.id",
2253 "/redfish/v1/Systems/system/LogServices/Dump/Entries"}};
2254 asyncResp->res.jsonValue["Actions"] = {
2255 {"#LogService.ClearLog",
2256 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2257 "LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002258 {"#LogService.CollectDiagnosticData",
2259 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2260 "LogService.CollectDiagnosticData"}}}};
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002261 }
2262};
2263
2264class SystemDumpEntryCollection : public Node
2265{
2266 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002267 SystemDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002268 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
2269 {
2270 entityPrivileges = {
2271 {boost::beast::http::verb::get, {{"Login"}}},
2272 {boost::beast::http::verb::head, {{"Login"}}},
2273 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2274 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2275 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2276 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2277 }
2278
2279 private:
2280 /**
2281 * Functions triggers appropriate requests on DBus
2282 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002283 void doGet(crow::Response& res, const crow::Request&,
2284 const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002285 {
2286 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2287
2288 asyncResp->res.jsonValue["@odata.type"] =
2289 "#LogEntryCollection.LogEntryCollection";
2290 asyncResp->res.jsonValue["@odata.id"] =
2291 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2292 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2293 asyncResp->res.jsonValue["Description"] =
2294 "Collection of System Dump Entries";
2295
2296 getDumpEntryCollection(asyncResp, "System");
2297 }
2298};
2299
2300class SystemDumpEntry : public Node
2301{
2302 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002303 SystemDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002304 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/",
2305 std::string())
2306 {
2307 entityPrivileges = {
2308 {boost::beast::http::verb::get, {{"Login"}}},
2309 {boost::beast::http::verb::head, {{"Login"}}},
2310 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2311 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2312 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2313 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2314 }
2315
2316 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002317 void doGet(crow::Response& res, const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002318 const std::vector<std::string>& params) override
2319 {
2320 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2321 if (params.size() != 1)
2322 {
2323 messages::internalError(asyncResp->res);
2324 return;
2325 }
2326 getDumpEntryById(asyncResp, params[0], "System");
2327 }
2328
Ed Tanouscb13a392020-07-25 19:02:03 +00002329 void doDelete(crow::Response& res, const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002330 const std::vector<std::string>& params) override
2331 {
2332 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2333 if (params.size() != 1)
2334 {
2335 messages::internalError(asyncResp->res);
2336 return;
2337 }
Stanley Chu98782562020-11-04 16:10:24 +08002338 deleteDumpEntry(asyncResp, params[0], "system");
raviteja-bc9bb6862020-02-03 11:53:32 -06002339 }
2340};
2341
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002342class SystemDumpCreate : public Node
2343{
2344 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002345 SystemDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002346 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002347 "Actions/"
2348 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002349 {
2350 entityPrivileges = {
2351 {boost::beast::http::verb::get, {{"Login"}}},
2352 {boost::beast::http::verb::head, {{"Login"}}},
2353 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2354 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2355 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2356 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2357 }
2358
2359 private:
2360 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002361 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002362 {
2363 createDump(res, req, "System");
2364 }
2365};
2366
raviteja-b013487e2020-03-03 03:20:48 -06002367class SystemDumpClear : public Node
2368{
2369 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002370 SystemDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002371 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
raviteja-b013487e2020-03-03 03:20:48 -06002372 "Actions/"
2373 "LogService.ClearLog/")
2374 {
2375 entityPrivileges = {
2376 {boost::beast::http::verb::get, {{"Login"}}},
2377 {boost::beast::http::verb::head, {{"Login"}}},
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002378 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2379 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2380 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
raviteja-b013487e2020-03-03 03:20:48 -06002381 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2382 }
2383
2384 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002385 void doPost(crow::Response& res, const crow::Request&,
2386 const std::vector<std::string>&) override
raviteja-b013487e2020-03-03 03:20:48 -06002387 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -05002388 clearDump(res, "System");
raviteja-b013487e2020-03-03 03:20:48 -06002389 }
2390};
2391
Jason M. Bills424c4172019-03-21 13:50:33 -07002392class CrashdumpService : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002393{
2394 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002395 CrashdumpService(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002396 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002397 {
AppaRao Puli39460282020-04-07 17:03:04 +05302398 // Note: Deviated from redfish privilege registry for GET & HEAD
2399 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002400 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302401 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2402 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002403 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2404 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2405 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2406 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002407 }
2408
2409 private:
2410 /**
2411 * Functions triggers appropriate requests on DBus
2412 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002413 void doGet(crow::Response& res, const crow::Request&,
2414 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002415 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002416 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002417 // Copy over the static data to include the entries added by SubRoute
Ed Tanous0f74e642018-11-12 15:17:05 -08002418 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002419 "/redfish/v1/Systems/system/LogServices/Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002420 asyncResp->res.jsonValue["@odata.type"] =
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002421 "#LogService.v1_2_0.LogService";
Gunnar Mills4f50ae42020-02-06 15:29:57 -06002422 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2423 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2424 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002425 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2426 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Jason M. Billscd50aa42019-02-12 17:09:02 -08002427 asyncResp->res.jsonValue["Entries"] = {
2428 {"@odata.id",
Jason M. Bills424c4172019-03-21 13:50:33 -07002429 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07002430 asyncResp->res.jsonValue["Actions"] = {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002431 {"#LogService.ClearLog",
2432 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2433 "Actions/LogService.ClearLog"}}},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002434 {"#LogService.CollectDiagnosticData",
2435 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2436 "Actions/LogService.CollectDiagnosticData"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002437
2438#ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002439 asyncResp->res.jsonValue["Actions"]["Oem"] = {
Jason M. Bills424c4172019-03-21 13:50:33 -07002440 {"#Crashdump.SendRawPeci",
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05002441 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002442 "Actions/Oem/Crashdump.SendRawPeci"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002443#endif
Ed Tanous1da66f72018-07-27 16:13:37 -07002444 }
2445};
2446
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002447class CrashdumpClear : public Node
2448{
2449 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002450 CrashdumpClear(App& app) :
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002451 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2452 "LogService.ClearLog/")
2453 {
AppaRao Puli39460282020-04-07 17:03:04 +05302454 // Note: Deviated from redfish privilege registry for GET & HEAD
2455 // method for security reasons.
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002456 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302457 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2458 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002459 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2460 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2461 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2462 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2463 }
2464
2465 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002466 void doPost(crow::Response& res, const crow::Request&,
2467 const std::vector<std::string>&) override
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002468 {
2469 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2470
2471 crow::connections::systemBus->async_method_call(
2472 [asyncResp](const boost::system::error_code ec,
Ed Tanouscb13a392020-07-25 19:02:03 +00002473 const std::string&) {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002474 if (ec)
2475 {
2476 messages::internalError(asyncResp->res);
2477 return;
2478 }
2479 messages::success(asyncResp->res);
2480 },
2481 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2482 }
2483};
2484
Ed Tanousb5a76932020-09-29 16:16:58 -07002485static void logCrashdumpEntry(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002486 const std::string& logID,
2487 nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002488{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002489 auto getStoredLogCallback =
2490 [asyncResp, logID, &logEntryJson](
2491 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002492 const std::vector<std::pair<std::string, VariantType>>& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002493 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002494 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002495 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2496 if (ec.value() ==
2497 boost::system::linux_error::bad_request_descriptor)
2498 {
2499 messages::resourceNotFound(asyncResp->res, "LogEntry",
2500 logID);
2501 }
2502 else
2503 {
2504 messages::internalError(asyncResp->res);
2505 }
2506 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002507 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002508
Johnathan Mantey043a0532020-03-10 17:15:28 -07002509 std::string timestamp{};
2510 std::string filename{};
2511 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002512 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002513
2514 if (filename.empty() || timestamp.empty())
2515 {
2516 messages::resourceMissingAtURI(asyncResp->res, logID);
2517 return;
2518 }
2519
2520 std::string crashdumpURI =
2521 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2522 logID + "/" + filename;
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002523 logEntryJson = {{"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002524 {"@odata.id", "/redfish/v1/Systems/system/"
2525 "LogServices/Crashdump/Entries/" +
2526 logID},
2527 {"Name", "CPU Crashdump"},
2528 {"Id", logID},
2529 {"EntryType", "Oem"},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002530 {"AdditionalDataURI", std::move(crashdumpURI)},
2531 {"DiagnosticDataType", "OEM"},
2532 {"OEMDiagnosticDataType", "PECICrashdump"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002533 {"Created", std::move(timestamp)}};
2534 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002535 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002536 std::move(getStoredLogCallback), crashdumpObject,
2537 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002538 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002539}
2540
Jason M. Bills424c4172019-03-21 13:50:33 -07002541class CrashdumpEntryCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002542{
2543 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002544 CrashdumpEntryCollection(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002545 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002546 {
AppaRao Puli39460282020-04-07 17:03:04 +05302547 // Note: Deviated from redfish privilege registry for GET & HEAD
2548 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002549 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302550 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2551 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002552 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2553 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2554 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2555 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002556 }
2557
2558 private:
2559 /**
2560 * Functions triggers appropriate requests on DBus
2561 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002562 void doGet(crow::Response& res, const crow::Request&,
2563 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002564 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002565 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002566 // Collections don't include the static data added by SubRoute because
2567 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07002568 auto getLogEntriesCallback = [asyncResp](
2569 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002570 const std::vector<std::string>& resp) {
Jason M. Billse1f26342018-07-18 12:12:00 -07002571 if (ec)
2572 {
2573 if (ec.value() !=
2574 boost::system::errc::no_such_file_or_directory)
Ed Tanous1da66f72018-07-27 16:13:37 -07002575 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002576 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2577 << ec.message();
Jason M. Billsf12894f2018-10-09 12:45:45 -07002578 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002579 return;
Ed Tanous1da66f72018-07-27 16:13:37 -07002580 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002581 }
2582 asyncResp->res.jsonValue["@odata.type"] =
2583 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002584 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002585 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Jason M. Bills424c4172019-03-21 13:50:33 -07002586 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002587 asyncResp->res.jsonValue["Description"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002588 "Collection of Crashdump Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002589 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07002590 logEntryArray = nlohmann::json::array();
Jason M. Billse855dd22019-10-08 11:37:48 -07002591 std::vector<std::string> logIDs;
2592 // Get the list of log entries and build up an empty array big
2593 // enough to hold them
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002594 for (const std::string& objpath : resp)
Jason M. Billse1f26342018-07-18 12:12:00 -07002595 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002596 // Get the log ID
Ed Tanousf23b7292020-10-15 09:41:17 -07002597 std::size_t lastPos = objpath.rfind('/');
Jason M. Billse855dd22019-10-08 11:37:48 -07002598 if (lastPos == std::string::npos)
Jason M. Billse1f26342018-07-18 12:12:00 -07002599 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002600 continue;
Jason M. Billse1f26342018-07-18 12:12:00 -07002601 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002602 logIDs.emplace_back(objpath.substr(lastPos + 1));
2603
2604 // Add a space for the log entry to the array
2605 logEntryArray.push_back({});
2606 }
2607 // Now go through and set up async calls to fill in the entries
2608 size_t index = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002609 for (const std::string& logID : logIDs)
Jason M. Billse855dd22019-10-08 11:37:48 -07002610 {
2611 // Add the log entry to the array
2612 logCrashdumpEntry(asyncResp, logID, logEntryArray[index++]);
Jason M. Billse1f26342018-07-18 12:12:00 -07002613 }
2614 asyncResp->res.jsonValue["Members@odata.count"] =
2615 logEntryArray.size();
2616 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002617 crow::connections::systemBus->async_method_call(
2618 std::move(getLogEntriesCallback),
2619 "xyz.openbmc_project.ObjectMapper",
2620 "/xyz/openbmc_project/object_mapper",
2621 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002622 std::array<const char*, 1>{crashdumpInterface});
Ed Tanous1da66f72018-07-27 16:13:37 -07002623 }
2624};
2625
Jason M. Bills424c4172019-03-21 13:50:33 -07002626class CrashdumpEntry : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002627{
2628 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002629 CrashdumpEntry(App& app) :
Jason M. Billsd53dd412019-02-12 17:16:22 -08002630 Node(app,
Jason M. Bills424c4172019-03-21 13:50:33 -07002631 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/",
Ed Tanous1da66f72018-07-27 16:13:37 -07002632 std::string())
2633 {
AppaRao Puli39460282020-04-07 17:03:04 +05302634 // Note: Deviated from redfish privilege registry for GET & HEAD
2635 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002636 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302637 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2638 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002639 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2640 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2641 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2642 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002643 }
2644
2645 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002646 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002647 const std::vector<std::string>& params) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002648 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002649 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002650 if (params.size() != 1)
2651 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002652 messages::internalError(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002653 return;
2654 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002655 const std::string& logID = params[0];
Jason M. Billse855dd22019-10-08 11:37:48 -07002656 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2657 }
2658};
2659
2660class CrashdumpFile : public Node
2661{
2662 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002663 CrashdumpFile(App& app) :
Jason M. Billse855dd22019-10-08 11:37:48 -07002664 Node(app,
2665 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/"
2666 "<str>/",
2667 std::string(), std::string())
2668 {
AppaRao Puli39460282020-04-07 17:03:04 +05302669 // Note: Deviated from redfish privilege registry for GET & HEAD
2670 // method for security reasons.
Jason M. Billse855dd22019-10-08 11:37:48 -07002671 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302672 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2673 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse855dd22019-10-08 11:37:48 -07002674 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2675 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2676 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2677 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2678 }
2679
2680 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002681 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002682 const std::vector<std::string>& params) override
Jason M. Billse855dd22019-10-08 11:37:48 -07002683 {
2684 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2685 if (params.size() != 2)
2686 {
2687 messages::internalError(asyncResp->res);
2688 return;
2689 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002690 const std::string& logID = params[0];
2691 const std::string& fileName = params[1];
Jason M. Billse855dd22019-10-08 11:37:48 -07002692
Johnathan Mantey043a0532020-03-10 17:15:28 -07002693 auto getStoredLogCallback =
2694 [asyncResp, logID, fileName](
2695 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002696 const std::vector<std::pair<std::string, VariantType>>& resp) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002697 if (ec)
2698 {
2699 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2700 << ec.message();
2701 messages::internalError(asyncResp->res);
2702 return;
2703 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002704
Johnathan Mantey043a0532020-03-10 17:15:28 -07002705 std::string dbusFilename{};
2706 std::string dbusTimestamp{};
2707 std::string dbusFilepath{};
Jason M. Billse855dd22019-10-08 11:37:48 -07002708
Ed Tanous2c70f802020-09-28 14:29:23 -07002709 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002710 dbusFilepath);
2711
2712 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2713 dbusFilepath.empty())
2714 {
2715 messages::resourceMissingAtURI(asyncResp->res, fileName);
2716 return;
2717 }
2718
2719 // Verify the file name parameter is correct
2720 if (fileName != dbusFilename)
2721 {
2722 messages::resourceMissingAtURI(asyncResp->res, fileName);
2723 return;
2724 }
2725
2726 if (!std::filesystem::exists(dbusFilepath))
2727 {
2728 messages::resourceMissingAtURI(asyncResp->res, fileName);
2729 return;
2730 }
2731 std::ifstream ifs(dbusFilepath, std::ios::in |
2732 std::ios::binary |
2733 std::ios::ate);
2734 std::ifstream::pos_type fileSize = ifs.tellg();
2735 if (fileSize < 0)
2736 {
2737 messages::generalError(asyncResp->res);
2738 return;
2739 }
2740 ifs.seekg(0, std::ios::beg);
2741
2742 auto crashData = std::make_unique<char[]>(
2743 static_cast<unsigned int>(fileSize));
2744
2745 ifs.read(crashData.get(), static_cast<int>(fileSize));
2746
2747 // The cast to std::string is intentional in order to use the
2748 // assign() that applies move mechanics
2749 asyncResp->res.body().assign(
2750 static_cast<std::string>(crashData.get()));
2751
2752 // Configure this to be a file download when accessed from
2753 // a browser
2754 asyncResp->res.addHeader("Content-Disposition", "attachment");
2755 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002756 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002757 std::move(getStoredLogCallback), crashdumpObject,
2758 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002759 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Ed Tanous1da66f72018-07-27 16:13:37 -07002760 }
2761};
2762
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002763class CrashdumpCollect : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002764{
2765 public:
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002766 CrashdumpCollect(App& app) :
2767 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2768 "LogService.CollectDiagnosticData/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002769 {
AppaRao Puli39460282020-04-07 17:03:04 +05302770 // Note: Deviated from redfish privilege registry for GET & HEAD
2771 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002772 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302773 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2774 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
2775 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2776 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2777 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2778 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002779 }
2780
2781 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002782 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002783 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002784 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002785 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002786
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002787 std::string diagnosticDataType;
2788 std::string oemDiagnosticDataType;
2789 if (!redfish::json_util::readJson(
2790 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2791 "OEMDiagnosticDataType", oemDiagnosticDataType))
2792 {
2793 return;
2794 }
2795
2796 if (diagnosticDataType != "OEM")
2797 {
2798 BMCWEB_LOG_ERROR
2799 << "Only OEM DiagnosticDataType supported for Crashdump";
2800 messages::actionParameterValueFormatError(
2801 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2802 "CollectDiagnosticData");
2803 return;
2804 }
2805
2806 auto collectCrashdumpCallback = [asyncResp, req](
2807 const boost::system::error_code ec,
2808 const std::string&) {
James Feist46229572020-02-19 15:11:58 -08002809 if (ec)
2810 {
2811 if (ec.value() == boost::system::errc::operation_not_supported)
Ed Tanous1da66f72018-07-27 16:13:37 -07002812 {
James Feist46229572020-02-19 15:11:58 -08002813 messages::resourceInStandby(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002814 }
James Feist46229572020-02-19 15:11:58 -08002815 else if (ec.value() ==
2816 boost::system::errc::device_or_resource_busy)
2817 {
2818 messages::serviceTemporarilyUnavailable(asyncResp->res,
2819 "60");
2820 }
2821 else
2822 {
2823 messages::internalError(asyncResp->res);
2824 }
2825 return;
2826 }
2827 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002828 [](boost::system::error_code err, sdbusplus::message::message&,
2829 const std::shared_ptr<task::TaskData>& taskData) {
James Feist66afe4f2020-02-24 13:09:58 -08002830 if (!err)
2831 {
James Feiste5d50062020-05-11 17:29:00 -07002832 taskData->messages.emplace_back(
2833 messages::taskCompletedOK(
2834 std::to_string(taskData->index)));
James Feist831d6b02020-03-12 16:31:30 -07002835 taskData->state = "Completed";
James Feist66afe4f2020-02-24 13:09:58 -08002836 }
James Feist32898ce2020-03-10 16:16:52 -07002837 return task::completed;
James Feist66afe4f2020-02-24 13:09:58 -08002838 },
James Feist46229572020-02-19 15:11:58 -08002839 "type='signal',interface='org.freedesktop.DBus.Properties',"
2840 "member='PropertiesChanged',arg0namespace='com.intel."
2841 "crashdump'");
2842 task->startTimer(std::chrono::minutes(5));
2843 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -07002844 task->payload.emplace(req);
James Feist46229572020-02-19 15:11:58 -08002845 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002846
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002847 if (oemDiagnosticDataType == "OnDemand")
2848 {
2849 crow::connections::systemBus->async_method_call(
2850 std::move(collectCrashdumpCallback), crashdumpObject,
2851 crashdumpPath, crashdumpOnDemandInterface,
2852 "GenerateOnDemandLog");
2853 }
2854 else if (oemDiagnosticDataType == "Telemetry")
2855 {
2856 crow::connections::systemBus->async_method_call(
2857 std::move(collectCrashdumpCallback), crashdumpObject,
2858 crashdumpPath, crashdumpTelemetryInterface,
2859 "GenerateTelemetryLog");
2860 }
2861 else
2862 {
2863 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
2864 << oemDiagnosticDataType;
2865 messages::actionParameterValueFormatError(
2866 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
2867 "CollectDiagnosticData");
2868 return;
2869 }
Kenny L. Ku6eda7682020-06-19 09:48:36 -07002870 }
2871};
2872
Jason M. Billse1f26342018-07-18 12:12:00 -07002873class SendRawPECI : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002874{
2875 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002876 SendRawPECI(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002877 Node(app,
2878 "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/Oem/"
2879 "Crashdump.SendRawPeci/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002880 {
AppaRao Puli39460282020-04-07 17:03:04 +05302881 // Note: Deviated from redfish privilege registry for GET & HEAD
2882 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002883 entityPrivileges = {
2884 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2885 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
2886 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2887 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2888 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2889 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2890 }
2891
2892 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002893 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002894 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002895 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002896 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002897 std::vector<std::vector<uint8_t>> peciCommands;
Ed Tanousb1556422018-10-16 14:09:17 -07002898
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002899 if (!json_util::readJson(req, res, "PECICommands", peciCommands))
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002900 {
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002901 return;
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002902 }
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002903 uint32_t idx = 0;
2904 for (auto const& cmd : peciCommands)
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002905 {
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002906 if (cmd.size() < 3)
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002907 {
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002908 std::string s("[");
2909 for (auto const& val : cmd)
2910 {
2911 if (val != *cmd.begin())
2912 {
2913 s += ",";
2914 }
2915 s += std::to_string(val);
2916 }
2917 s += "]";
2918 messages::actionParameterValueFormatError(
2919 res, s, "PECICommands[" + std::to_string(idx) + "]",
2920 "SendRawPeci");
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002921 return;
2922 }
Karthick Sundarrajanf0b6ae02020-01-17 13:32:58 -08002923 idx++;
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002924 }
Ed Tanous1da66f72018-07-27 16:13:37 -07002925 // Callback to return the Raw PECI response
Jason M. Billse1f26342018-07-18 12:12:00 -07002926 auto sendRawPECICallback =
2927 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002928 const std::vector<std::vector<uint8_t>>& resp) {
Jason M. Billse1f26342018-07-18 12:12:00 -07002929 if (ec)
2930 {
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002931 BMCWEB_LOG_DEBUG << "failed to process PECI commands ec: "
Jason M. Billse1f26342018-07-18 12:12:00 -07002932 << ec.message();
Jason M. Billsf12894f2018-10-09 12:45:45 -07002933 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002934 return;
2935 }
2936 asyncResp->res.jsonValue = {{"Name", "PECI Command Response"},
2937 {"PECIResponse", resp}};
2938 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002939 // Call the SendRawPECI command with the provided data
2940 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002941 std::move(sendRawPECICallback), crashdumpObject, crashdumpPath,
Karthick Sundarrajan8724c292020-01-06 09:04:48 -08002942 crashdumpRawPECIInterface, "SendRawPeci", peciCommands);
Ed Tanous1da66f72018-07-27 16:13:37 -07002943 }
2944};
2945
Andrew Geisslercb92c032018-08-17 07:56:14 -07002946/**
2947 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
2948 */
2949class DBusLogServiceActionsClear : public Node
2950{
2951 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002952 DBusLogServiceActionsClear(App& app) :
Andrew Geisslercb92c032018-08-17 07:56:14 -07002953 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
Gunnar Mills7af91512020-04-14 22:16:57 -05002954 "LogService.ClearLog/")
Andrew Geisslercb92c032018-08-17 07:56:14 -07002955 {
2956 entityPrivileges = {
2957 {boost::beast::http::verb::get, {{"Login"}}},
2958 {boost::beast::http::verb::head, {{"Login"}}},
2959 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2960 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2961 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2962 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2963 }
2964
2965 private:
2966 /**
2967 * Function handles POST method request.
2968 * The Clear Log actions does not require any parameter.The action deletes
2969 * all entries found in the Entries collection for this Log Service.
2970 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002971 void doPost(crow::Response& res, const crow::Request&,
2972 const std::vector<std::string>&) override
Andrew Geisslercb92c032018-08-17 07:56:14 -07002973 {
2974 BMCWEB_LOG_DEBUG << "Do delete all entries.";
2975
2976 auto asyncResp = std::make_shared<AsyncResp>(res);
2977 // Process response from Logging service.
Ed Tanous2c70f802020-09-28 14:29:23 -07002978 auto respHandler = [asyncResp](const boost::system::error_code ec) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07002979 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
2980 if (ec)
2981 {
2982 // TODO Handle for specific error code
2983 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
2984 asyncResp->res.result(
2985 boost::beast::http::status::internal_server_error);
2986 return;
2987 }
2988
2989 asyncResp->res.result(boost::beast::http::status::no_content);
2990 };
2991
2992 // Make call to Logging service to request Clear Log
2993 crow::connections::systemBus->async_method_call(
Ed Tanous2c70f802020-09-28 14:29:23 -07002994 respHandler, "xyz.openbmc_project.Logging",
Andrew Geisslercb92c032018-08-17 07:56:14 -07002995 "/xyz/openbmc_project/logging",
2996 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
2997 }
2998};
ZhikuiRena3316fc2020-01-29 14:58:08 -08002999
3000/****************************************************
3001 * Redfish PostCode interfaces
3002 * using DBUS interface: getPostCodesTS
3003 ******************************************************/
3004class PostCodesLogService : public Node
3005{
3006 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003007 PostCodesLogService(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003008 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
3009 {
3010 entityPrivileges = {
3011 {boost::beast::http::verb::get, {{"Login"}}},
3012 {boost::beast::http::verb::head, {{"Login"}}},
3013 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3014 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3015 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3016 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3017 }
3018
3019 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003020 void doGet(crow::Response& res, const crow::Request&,
3021 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003022 {
3023 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3024
3025 asyncResp->res.jsonValue = {
3026 {"@odata.id", "/redfish/v1/Systems/system/LogServices/PostCodes"},
3027 {"@odata.type", "#LogService.v1_1_0.LogService"},
ZhikuiRena3316fc2020-01-29 14:58:08 -08003028 {"Name", "POST Code Log Service"},
3029 {"Description", "POST Code Log Service"},
3030 {"Id", "BIOS POST Code Log"},
3031 {"OverWritePolicy", "WrapsWhenFull"},
3032 {"Entries",
3033 {{"@odata.id",
3034 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"}}}};
3035 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3036 {"target", "/redfish/v1/Systems/system/LogServices/PostCodes/"
3037 "Actions/LogService.ClearLog"}};
3038 }
3039};
3040
3041class PostCodesClear : public Node
3042{
3043 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003044 PostCodesClear(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003045 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/"
3046 "LogService.ClearLog/")
3047 {
3048 entityPrivileges = {
3049 {boost::beast::http::verb::get, {{"Login"}}},
3050 {boost::beast::http::verb::head, {{"Login"}}},
AppaRao Puli39460282020-04-07 17:03:04 +05303051 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
3052 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
3053 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
3054 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003055 }
3056
3057 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003058 void doPost(crow::Response& res, const crow::Request&,
3059 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003060 {
3061 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
3062
3063 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3064 // Make call to post-code service to request clear all
3065 crow::connections::systemBus->async_method_call(
3066 [asyncResp](const boost::system::error_code ec) {
3067 if (ec)
3068 {
3069 // TODO Handle for specific error code
3070 BMCWEB_LOG_ERROR
3071 << "doClearPostCodes resp_handler got error " << ec;
3072 asyncResp->res.result(
3073 boost::beast::http::status::internal_server_error);
3074 messages::internalError(asyncResp->res);
3075 return;
3076 }
3077 },
Jonathan Doman15124762021-01-07 17:54:17 -08003078 "xyz.openbmc_project.State.Boot.PostCode0",
3079 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003080 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3081 }
3082};
3083
3084static void fillPostCodeEntry(
Ed Tanousb5a76932020-09-29 16:16:58 -07003085 const std::shared_ptr<AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303086 const boost::container::flat_map<
3087 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003088 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3089 const uint64_t skip = 0, const uint64_t top = 0)
3090{
3091 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003092 const message_registries::Message* message =
ZhikuiRena3316fc2020-01-29 14:58:08 -08003093 message_registries::getMessage("OpenBMC.0.1.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003094
3095 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003096 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003097
3098 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303099 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3100 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003101 {
3102 currentCodeIndex++;
3103 std::string postcodeEntryID =
3104 "B" + std::to_string(bootIndex) + "-" +
3105 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3106
3107 uint64_t usecSinceEpoch = code.first;
3108 uint64_t usTimeOffset = 0;
3109
3110 if (1 == currentCodeIndex)
3111 { // already incremented
3112 firstCodeTimeUs = code.first;
3113 }
3114 else
3115 {
3116 usTimeOffset = code.first - firstCodeTimeUs;
3117 }
3118
3119 // skip if no specific codeIndex is specified and currentCodeIndex does
3120 // not fall between top and skip
3121 if ((codeIndex == 0) &&
3122 (currentCodeIndex <= skip || currentCodeIndex > top))
3123 {
3124 continue;
3125 }
3126
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003127 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003128 // currentIndex
3129 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3130 {
3131 // This is done for simplicity. 1st entry is needed to calculate
3132 // time offset. To improve efficiency, one can get to the entry
3133 // directly (possibly with flatmap's nth method)
3134 continue;
3135 }
3136
3137 // currentCodeIndex is within top and skip or equal to specified code
3138 // index
3139
3140 // Get the Created time from the timestamp
3141 std::string entryTimeStr;
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -05003142 entryTimeStr = crow::utility::getDateTime(
3143 static_cast<std::time_t>(usecSinceEpoch / 1000 / 1000));
ZhikuiRena3316fc2020-01-29 14:58:08 -08003144
3145 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3146 std::ostringstream hexCode;
3147 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303148 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003149 std::ostringstream timeOffsetStr;
3150 // Set Fixed -Point Notation
3151 timeOffsetStr << std::fixed;
3152 // Set precision to 4 digits
3153 timeOffsetStr << std::setprecision(4);
3154 // Add double to stream
3155 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3156 std::vector<std::string> messageArgs = {
3157 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3158
3159 // Get MessageArgs template from message registry
3160 std::string msg;
3161 if (message != nullptr)
3162 {
3163 msg = message->message;
3164
3165 // fill in this post code value
3166 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003167 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003168 {
3169 std::string argStr = "%" + std::to_string(++i);
3170 size_t argPos = msg.find(argStr);
3171 if (argPos != std::string::npos)
3172 {
3173 msg.replace(argPos, argStr.length(), messageArg);
3174 }
3175 }
3176 }
3177
Tim Leed4342a92020-04-27 11:47:58 +08003178 // Get Severity template from message registry
3179 std::string severity;
3180 if (message != nullptr)
3181 {
3182 severity = message->severity;
3183 }
3184
ZhikuiRena3316fc2020-01-29 14:58:08 -08003185 // add to AsyncResp
3186 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003187 nlohmann::json& bmcLogEntry = logEntryArray.back();
Gunnar Mills743e9a12020-10-26 12:44:53 -05003188 bmcLogEntry = {{"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
3189 {"@odata.id", "/redfish/v1/Systems/system/LogServices/"
3190 "PostCodes/Entries/" +
3191 postcodeEntryID},
3192 {"Name", "POST Code Log Entry"},
3193 {"Id", postcodeEntryID},
3194 {"Message", std::move(msg)},
3195 {"MessageId", "OpenBMC.0.1.BIOSPOSTCode"},
3196 {"MessageArgs", std::move(messageArgs)},
3197 {"EntryType", "Event"},
3198 {"Severity", std::move(severity)},
3199 {"Created", entryTimeStr}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003200 }
3201}
3202
Ed Tanousb5a76932020-09-29 16:16:58 -07003203static void getPostCodeForEntry(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003204 const uint16_t bootIndex,
3205 const uint64_t codeIndex)
3206{
3207 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303208 [aResp, bootIndex,
3209 codeIndex](const boost::system::error_code ec,
3210 const boost::container::flat_map<
3211 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3212 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003213 if (ec)
3214 {
3215 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3216 messages::internalError(aResp->res);
3217 return;
3218 }
3219
3220 // skip the empty postcode boots
3221 if (postcode.empty())
3222 {
3223 return;
3224 }
3225
3226 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3227
3228 aResp->res.jsonValue["Members@odata.count"] =
3229 aResp->res.jsonValue["Members"].size();
3230 },
Jonathan Doman15124762021-01-07 17:54:17 -08003231 "xyz.openbmc_project.State.Boot.PostCode0",
3232 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003233 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3234 bootIndex);
3235}
3236
Ed Tanousb5a76932020-09-29 16:16:58 -07003237static void getPostCodeForBoot(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003238 const uint16_t bootIndex,
3239 const uint16_t bootCount,
3240 const uint64_t entryCount, const uint64_t skip,
3241 const uint64_t top)
3242{
3243 crow::connections::systemBus->async_method_call(
3244 [aResp, bootIndex, bootCount, entryCount, skip,
3245 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303246 const boost::container::flat_map<
3247 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3248 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003249 if (ec)
3250 {
3251 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3252 messages::internalError(aResp->res);
3253 return;
3254 }
3255
3256 uint64_t endCount = entryCount;
3257 if (!postcode.empty())
3258 {
3259 endCount = entryCount + postcode.size();
3260
3261 if ((skip < endCount) && ((top + skip) > entryCount))
3262 {
3263 uint64_t thisBootSkip =
3264 std::max(skip, entryCount) - entryCount;
3265 uint64_t thisBootTop =
3266 std::min(top + skip, endCount) - entryCount;
3267
3268 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3269 thisBootSkip, thisBootTop);
3270 }
3271 aResp->res.jsonValue["Members@odata.count"] = endCount;
3272 }
3273
3274 // continue to previous bootIndex
3275 if (bootIndex < bootCount)
3276 {
3277 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3278 bootCount, endCount, skip, top);
3279 }
3280 else
3281 {
3282 aResp->res.jsonValue["Members@odata.nextLink"] =
3283 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3284 "Entries?$skip=" +
3285 std::to_string(skip + top);
3286 }
3287 },
Jonathan Doman15124762021-01-07 17:54:17 -08003288 "xyz.openbmc_project.State.Boot.PostCode0",
3289 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003290 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3291 bootIndex);
3292}
3293
Ed Tanousb5a76932020-09-29 16:16:58 -07003294static void getCurrentBootNumber(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003295 const uint64_t skip, const uint64_t top)
3296{
3297 uint64_t entryCount = 0;
3298 crow::connections::systemBus->async_method_call(
3299 [aResp, entryCount, skip,
3300 top](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003301 const std::variant<uint16_t>& bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003302 if (ec)
3303 {
3304 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3305 messages::internalError(aResp->res);
3306 return;
3307 }
3308 auto pVal = std::get_if<uint16_t>(&bootCount);
3309 if (pVal)
3310 {
3311 getPostCodeForBoot(aResp, 1, *pVal, entryCount, skip, top);
3312 }
3313 else
3314 {
3315 BMCWEB_LOG_DEBUG << "Post code boot index failed.";
3316 }
3317 },
Jonathan Doman15124762021-01-07 17:54:17 -08003318 "xyz.openbmc_project.State.Boot.PostCode0",
3319 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003320 "org.freedesktop.DBus.Properties", "Get",
3321 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount");
3322}
3323
3324class PostCodesEntryCollection : public Node
3325{
3326 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003327 PostCodesEntryCollection(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003328 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
3329 {
3330 entityPrivileges = {
3331 {boost::beast::http::verb::get, {{"Login"}}},
3332 {boost::beast::http::verb::head, {{"Login"}}},
3333 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3334 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3335 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3336 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3337 }
3338
3339 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003340 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00003341 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003342 {
3343 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3344
3345 asyncResp->res.jsonValue["@odata.type"] =
3346 "#LogEntryCollection.LogEntryCollection";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003347 asyncResp->res.jsonValue["@odata.id"] =
3348 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3349 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3350 asyncResp->res.jsonValue["Description"] =
3351 "Collection of POST Code Log Entries";
3352 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3353 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3354
3355 uint64_t skip = 0;
3356 uint64_t top = maxEntriesPerPage; // Show max entries by default
3357 if (!getSkipParam(asyncResp->res, req, skip))
3358 {
3359 return;
3360 }
3361 if (!getTopParam(asyncResp->res, req, top))
3362 {
3363 return;
3364 }
3365 getCurrentBootNumber(asyncResp, skip, top);
3366 }
3367};
3368
3369class PostCodesEntry : public Node
3370{
3371 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003372 PostCodesEntry(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003373 Node(app,
3374 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/",
3375 std::string())
3376 {
3377 entityPrivileges = {
3378 {boost::beast::http::verb::get, {{"Login"}}},
3379 {boost::beast::http::verb::head, {{"Login"}}},
3380 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3381 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3382 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3383 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3384 }
3385
3386 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003387 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003388 const std::vector<std::string>& params) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003389 {
3390 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3391 if (params.size() != 1)
3392 {
3393 messages::internalError(asyncResp->res);
3394 return;
3395 }
3396
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003397 const std::string& targetID = params[0];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003398
3399 size_t bootPos = targetID.find('B');
3400 if (bootPos == std::string::npos)
3401 {
3402 // Requested ID was not found
3403 messages::resourceMissingAtURI(asyncResp->res, targetID);
3404 return;
3405 }
3406 std::string_view bootIndexStr(targetID);
3407 bootIndexStr.remove_prefix(bootPos + 1);
3408 uint16_t bootIndex = 0;
3409 uint64_t codeIndex = 0;
3410 size_t dashPos = bootIndexStr.find('-');
3411
3412 if (dashPos == std::string::npos)
3413 {
3414 return;
3415 }
3416 std::string_view codeIndexStr(bootIndexStr);
3417 bootIndexStr.remove_suffix(dashPos);
3418 codeIndexStr.remove_prefix(dashPos + 1);
3419
3420 bootIndex = static_cast<uint16_t>(
Ed Tanous23a21a12020-07-25 04:45:05 +00003421 strtoul(std::string(bootIndexStr).c_str(), nullptr, 0));
3422 codeIndex = strtoul(std::string(codeIndexStr).c_str(), nullptr, 0);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003423 if (bootIndex == 0 || codeIndex == 0)
3424 {
3425 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3426 << params[0];
3427 }
3428
3429 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003430 asyncResp->res.jsonValue["@odata.id"] =
3431 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3432 "Entries";
3433 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3434 asyncResp->res.jsonValue["Description"] =
3435 "Collection of POST Code Log Entries";
3436 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3437 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3438
3439 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3440 }
3441};
3442
Ed Tanous1da66f72018-07-27 16:13:37 -07003443} // namespace redfish