blob: 7614ec05d7f6c3652f0332901149bdb9f688d080 [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>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060025#include <unistd.h>
Jason M. Billse1f26342018-07-18 12:12:00 -070026
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060027#include <boost/algorithm/string/replace.hpp>
Jason M. Bills4851d452019-03-28 11:27:48 -070028#include <boost/algorithm/string/split.hpp>
29#include <boost/beast/core/span.hpp>
Adriana Kobylak400fd1f2021-01-29 09:01:30 -060030#include <boost/beast/http.hpp>
Ed Tanous1da66f72018-07-27 16:13:37 -070031#include <boost/container/flat_map.hpp>
Jason M. Bills1ddcf012019-11-26 14:59:21 -080032#include <boost/system/linux_error.hpp>
Andrew Geisslercb92c032018-08-17 07:56:14 -070033#include <error_messages.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034
James Feist4418c7f2019-04-15 11:09:15 -070035#include <filesystem>
Xiaochao Ma75710de2021-01-21 17:56:02 +080036#include <optional>
Jason M. Billscd225da2019-05-08 15:31:57 -070037#include <string_view>
Ed Tanousabf2add2019-01-22 16:40:12 -080038#include <variant>
Ed Tanous1da66f72018-07-27 16:13:37 -070039
40namespace redfish
41{
42
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043constexpr char const* crashdumpObject = "com.intel.crashdump";
44constexpr char const* crashdumpPath = "/com/intel/crashdump";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045constexpr char const* crashdumpInterface = "com.intel.crashdump";
46constexpr char const* deleteAllInterface =
Jason M. Bills5b61b5e2019-10-16 10:59:02 -070047 "xyz.openbmc_project.Collection.DeleteAll";
Gunnar Mills1214b7e2020-06-04 10:11:30 -050048constexpr char const* crashdumpOnDemandInterface =
Jason M. Bills424c4172019-03-21 13:50:33 -070049 "com.intel.crashdump.OnDemand";
Kenny L. Ku6eda7682020-06-19 09:48:36 -070050constexpr char const* crashdumpTelemetryInterface =
51 "com.intel.crashdump.Telemetry";
Ed Tanous1da66f72018-07-27 16:13:37 -070052
Jason M. Bills4851d452019-03-28 11:27:48 -070053namespace message_registries
54{
Gunnar Mills1214b7e2020-06-04 10:11:30 -050055static const Message* getMessageFromRegistry(
56 const std::string& messageKey,
Jason M. Bills4851d452019-03-28 11:27:48 -070057 const boost::beast::span<const MessageEntry> registry)
58{
59 boost::beast::span<const MessageEntry>::const_iterator messageIt =
60 std::find_if(registry.cbegin(), registry.cend(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -050061 [&messageKey](const MessageEntry& messageEntry) {
Jason M. Bills4851d452019-03-28 11:27:48 -070062 return !std::strcmp(messageEntry.first,
63 messageKey.c_str());
64 });
65 if (messageIt != registry.cend())
66 {
67 return &messageIt->second;
68 }
69
70 return nullptr;
71}
72
Gunnar Mills1214b7e2020-06-04 10:11:30 -050073static const Message* getMessage(const std::string_view& messageID)
Jason M. Bills4851d452019-03-28 11:27:48 -070074{
75 // Redfish MessageIds are in the form
76 // RegistryName.MajorVersion.MinorVersion.MessageKey, so parse it to find
77 // the right Message
78 std::vector<std::string> fields;
79 fields.reserve(4);
80 boost::split(fields, messageID, boost::is_any_of("."));
Gunnar Mills1214b7e2020-06-04 10:11:30 -050081 std::string& registryName = fields[0];
82 std::string& messageKey = fields[3];
Jason M. Bills4851d452019-03-28 11:27:48 -070083
84 // Find the right registry and check it for the MessageKey
85 if (std::string(base::header.registryPrefix) == registryName)
86 {
87 return getMessageFromRegistry(
88 messageKey, boost::beast::span<const MessageEntry>(base::registry));
89 }
90 if (std::string(openbmc::header.registryPrefix) == registryName)
91 {
92 return getMessageFromRegistry(
93 messageKey,
94 boost::beast::span<const MessageEntry>(openbmc::registry));
95 }
96 return nullptr;
97}
98} // namespace message_registries
99
James Feistf6150402019-01-08 10:36:20 -0800100namespace fs = std::filesystem;
Ed Tanous1da66f72018-07-27 16:13:37 -0700101
Andrew Geisslercb92c032018-08-17 07:56:14 -0700102using GetManagedPropertyType = boost::container::flat_map<
Patrick Williams19bd78d2020-05-13 17:38:24 -0500103 std::string, std::variant<std::string, bool, uint8_t, int16_t, uint16_t,
104 int32_t, uint32_t, int64_t, uint64_t, double>>;
Andrew Geisslercb92c032018-08-17 07:56:14 -0700105
106using GetManagedObjectsType = boost::container::flat_map<
107 sdbusplus::message::object_path,
108 boost::container::flat_map<std::string, GetManagedPropertyType>>;
109
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500110inline std::string translateSeverityDbusToRedfish(const std::string& s)
Andrew Geisslercb92c032018-08-17 07:56:14 -0700111{
Ed Tanousd4d25792020-09-29 15:15:03 -0700112 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Alert") ||
113 (s == "xyz.openbmc_project.Logging.Entry.Level.Critical") ||
114 (s == "xyz.openbmc_project.Logging.Entry.Level.Emergency") ||
115 (s == "xyz.openbmc_project.Logging.Entry.Level.Error"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700116 {
117 return "Critical";
118 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700119 if ((s == "xyz.openbmc_project.Logging.Entry.Level.Debug") ||
120 (s == "xyz.openbmc_project.Logging.Entry.Level.Informational") ||
121 (s == "xyz.openbmc_project.Logging.Entry.Level.Notice"))
Andrew Geisslercb92c032018-08-17 07:56:14 -0700122 {
123 return "OK";
124 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700125 if (s == "xyz.openbmc_project.Logging.Entry.Level.Warning")
Andrew Geisslercb92c032018-08-17 07:56:14 -0700126 {
127 return "Warning";
128 }
129 return "";
130}
131
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500132static int getJournalMetadata(sd_journal* journal,
133 const std::string_view& field,
134 std::string_view& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700135{
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500136 const char* data = nullptr;
Jason M. Bills16428a12018-11-02 12:42:29 -0700137 size_t length = 0;
138 int ret = 0;
139 // Get the metadata from the requested field of the journal entry
Ed Tanous271584a2019-07-09 16:24:22 -0700140 ret = sd_journal_get_data(journal, field.data(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500141 reinterpret_cast<const void**>(&data), &length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700142 if (ret < 0)
143 {
144 return ret;
145 }
Ed Tanous39e77502019-03-04 17:35:53 -0800146 contents = std::string_view(data, length);
Jason M. Bills16428a12018-11-02 12:42:29 -0700147 // Only use the content after the "=" character.
Ed Tanous81ce6092020-12-17 16:54:55 +0000148 contents.remove_prefix(std::min(contents.find('=') + 1, contents.size()));
Jason M. Bills16428a12018-11-02 12:42:29 -0700149 return ret;
150}
151
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500152static int getJournalMetadata(sd_journal* journal,
153 const std::string_view& field, const int& base,
154 long int& contents)
Jason M. Bills16428a12018-11-02 12:42:29 -0700155{
156 int ret = 0;
Ed Tanous39e77502019-03-04 17:35:53 -0800157 std::string_view metadata;
Jason M. Bills16428a12018-11-02 12:42:29 -0700158 // Get the metadata from the requested field of the journal entry
159 ret = getJournalMetadata(journal, field, metadata);
160 if (ret < 0)
161 {
162 return ret;
163 }
Ed Tanousb01bf292019-03-25 19:25:26 +0000164 contents = strtol(metadata.data(), nullptr, base);
Jason M. Bills16428a12018-11-02 12:42:29 -0700165 return ret;
166}
167
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500168static bool getEntryTimestamp(sd_journal* journal, std::string& entryTimestamp)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800169{
170 int ret = 0;
171 uint64_t timestamp = 0;
172 ret = sd_journal_get_realtime_usec(journal, &timestamp);
173 if (ret < 0)
174 {
175 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
176 << strerror(-ret);
177 return false;
178 }
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -0500179 entryTimestamp = crow::utility::getDateTime(
180 static_cast<std::time_t>(timestamp / 1000 / 1000));
181 return true;
ZhikuiRena3316fc2020-01-29 14:58:08 -0800182}
183
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500184static bool getSkipParam(crow::Response& res, const crow::Request& req,
185 uint64_t& skip)
Jason M. Bills16428a12018-11-02 12:42:29 -0700186{
James Feist5a7e8772020-07-22 09:08:38 -0700187 boost::urls::url_view::params_type::iterator it =
188 req.urlParams.find("$skip");
189 if (it != req.urlParams.end())
Jason M. Bills16428a12018-11-02 12:42:29 -0700190 {
James Feist5a7e8772020-07-22 09:08:38 -0700191 std::string skipParam = it->value();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500192 char* ptr = nullptr;
James Feist5a7e8772020-07-22 09:08:38 -0700193 skip = std::strtoul(skipParam.c_str(), &ptr, 10);
194 if (skipParam.empty() || *ptr != '\0')
Jason M. Bills16428a12018-11-02 12:42:29 -0700195 {
196
197 messages::queryParameterValueTypeError(res, std::string(skipParam),
198 "$skip");
199 return false;
200 }
Jason M. Bills16428a12018-11-02 12:42:29 -0700201 }
202 return true;
203}
204
Ed Tanous271584a2019-07-09 16:24:22 -0700205static constexpr const uint64_t maxEntriesPerPage = 1000;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500206static bool getTopParam(crow::Response& res, const crow::Request& req,
207 uint64_t& top)
Jason M. Bills16428a12018-11-02 12:42:29 -0700208{
James Feist5a7e8772020-07-22 09:08:38 -0700209 boost::urls::url_view::params_type::iterator it =
210 req.urlParams.find("$top");
211 if (it != req.urlParams.end())
Jason M. Bills16428a12018-11-02 12:42:29 -0700212 {
James Feist5a7e8772020-07-22 09:08:38 -0700213 std::string topParam = it->value();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500214 char* ptr = nullptr;
James Feist5a7e8772020-07-22 09:08:38 -0700215 top = std::strtoul(topParam.c_str(), &ptr, 10);
216 if (topParam.empty() || *ptr != '\0')
Jason M. Bills16428a12018-11-02 12:42:29 -0700217 {
218 messages::queryParameterValueTypeError(res, std::string(topParam),
219 "$top");
220 return false;
221 }
Ed Tanous271584a2019-07-09 16:24:22 -0700222 if (top < 1U || top > maxEntriesPerPage)
Jason M. Bills16428a12018-11-02 12:42:29 -0700223 {
224
225 messages::queryParameterOutOfRange(
226 res, std::to_string(top), "$top",
227 "1-" + std::to_string(maxEntriesPerPage));
228 return false;
229 }
230 }
231 return true;
232}
233
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234static bool getUniqueEntryID(sd_journal* journal, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700235 const bool firstEntry = true)
Jason M. Bills16428a12018-11-02 12:42:29 -0700236{
237 int ret = 0;
238 static uint64_t prevTs = 0;
239 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700240 if (firstEntry)
241 {
242 prevTs = 0;
243 }
244
Jason M. Bills16428a12018-11-02 12:42:29 -0700245 // Get the entry timestamp
246 uint64_t curTs = 0;
247 ret = sd_journal_get_realtime_usec(journal, &curTs);
248 if (ret < 0)
249 {
250 BMCWEB_LOG_ERROR << "Failed to read entry timestamp: "
251 << strerror(-ret);
252 return false;
253 }
254 // If the timestamp isn't unique, increment the index
255 if (curTs == prevTs)
256 {
257 index++;
258 }
259 else
260 {
261 // Otherwise, reset it
262 index = 0;
263 }
264 // Save the timestamp
265 prevTs = curTs;
266
267 entryID = std::to_string(curTs);
268 if (index > 0)
269 {
270 entryID += "_" + std::to_string(index);
271 }
272 return true;
273}
274
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500275static bool getUniqueEntryID(const std::string& logEntry, std::string& entryID,
Jason M. Billse85d6b12019-07-29 17:01:15 -0700276 const bool firstEntry = true)
Jason M. Bills95820182019-04-22 16:25:34 -0700277{
Ed Tanous271584a2019-07-09 16:24:22 -0700278 static time_t prevTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700279 static int index = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -0700280 if (firstEntry)
281 {
282 prevTs = 0;
283 }
284
Jason M. Bills95820182019-04-22 16:25:34 -0700285 // Get the entry timestamp
Ed Tanous271584a2019-07-09 16:24:22 -0700286 std::time_t curTs = 0;
Jason M. Bills95820182019-04-22 16:25:34 -0700287 std::tm timeStruct = {};
288 std::istringstream entryStream(logEntry);
289 if (entryStream >> std::get_time(&timeStruct, "%Y-%m-%dT%H:%M:%S"))
290 {
291 curTs = std::mktime(&timeStruct);
292 }
293 // If the timestamp isn't unique, increment the index
294 if (curTs == prevTs)
295 {
296 index++;
297 }
298 else
299 {
300 // Otherwise, reset it
301 index = 0;
302 }
303 // Save the timestamp
304 prevTs = curTs;
305
306 entryID = std::to_string(curTs);
307 if (index > 0)
308 {
309 entryID += "_" + std::to_string(index);
310 }
311 return true;
312}
313
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500314static bool getTimestampFromID(crow::Response& res, const std::string& entryID,
315 uint64_t& timestamp, uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700316{
317 if (entryID.empty())
318 {
319 return false;
320 }
321 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800322 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700323
Ed Tanous81ce6092020-12-17 16:54:55 +0000324 auto underscorePos = tsStr.find('_');
Jason M. Bills16428a12018-11-02 12:42:29 -0700325 if (underscorePos != tsStr.npos)
326 {
327 // Timestamp has an index
328 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800329 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700330 indexStr.remove_prefix(underscorePos + 1);
331 std::size_t pos;
332 try
333 {
Ed Tanous39e77502019-03-04 17:35:53 -0800334 index = std::stoul(std::string(indexStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700335 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500336 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700337 {
338 messages::resourceMissingAtURI(res, entryID);
339 return false;
340 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500341 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700342 {
343 messages::resourceMissingAtURI(res, entryID);
344 return false;
345 }
346 if (pos != indexStr.size())
347 {
348 messages::resourceMissingAtURI(res, entryID);
349 return false;
350 }
351 }
352 // Timestamp has no index
353 std::size_t pos;
354 try
355 {
Ed Tanous39e77502019-03-04 17:35:53 -0800356 timestamp = std::stoull(std::string(tsStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700357 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500358 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700359 {
360 messages::resourceMissingAtURI(res, entryID);
361 return false;
362 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500363 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700364 {
365 messages::resourceMissingAtURI(res, entryID);
366 return false;
367 }
368 if (pos != tsStr.size())
369 {
370 messages::resourceMissingAtURI(res, entryID);
371 return false;
372 }
373 return true;
374}
375
Jason M. Bills95820182019-04-22 16:25:34 -0700376static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500377 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700378{
379 static const std::filesystem::path redfishLogDir = "/var/log";
380 static const std::string redfishLogFilename = "redfish";
381
382 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500383 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700384 std::filesystem::directory_iterator(redfishLogDir))
385 {
386 // If we find a redfish log file, save the path
387 std::string filename = dirEnt.path().filename();
388 if (boost::starts_with(filename, redfishLogFilename))
389 {
390 redfishLogFiles.emplace_back(redfishLogDir / filename);
391 }
392 }
393 // As the log files rotate, they are appended with a ".#" that is higher for
394 // the older logs. Since we don't expect more than 10 log files, we
395 // can just sort the list to get them in order from newest to oldest
396 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
397
398 return !redfishLogFiles.empty();
399}
400
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500401inline void getDumpEntryCollection(std::shared_ptr<AsyncResp>& asyncResp,
402 const std::string& dumpType)
403{
404 std::string dumpPath;
405 if (dumpType == "BMC")
406 {
407 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
408 }
409 else if (dumpType == "System")
410 {
411 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
412 }
413 else
414 {
415 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
416 messages::internalError(asyncResp->res);
417 return;
418 }
419
420 crow::connections::systemBus->async_method_call(
421 [asyncResp, dumpPath, dumpType](const boost::system::error_code ec,
422 GetManagedObjectsType& resp) {
423 if (ec)
424 {
425 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
426 messages::internalError(asyncResp->res);
427 return;
428 }
429
430 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
431 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500432 std::string dumpEntryPath =
433 "/xyz/openbmc_project/dump/" +
434 std::string(boost::algorithm::to_lower_copy(dumpType)) +
435 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500436
437 for (auto& object : resp)
438 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500439 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500440 {
441 continue;
442 }
443 std::time_t timestamp;
444 uint64_t size = 0;
445 entriesArray.push_back({});
446 nlohmann::json& thisEntry = entriesArray.back();
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000447
448 std::string entryID = object.first.filename();
449 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500450 {
451 continue;
452 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500453
454 for (auto& interfaceMap : object.second)
455 {
456 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
457 {
458
459 for (auto& propertyMap : interfaceMap.second)
460 {
461 if (propertyMap.first == "Size")
462 {
463 auto sizePtr =
464 std::get_if<uint64_t>(&propertyMap.second);
465 if (sizePtr == nullptr)
466 {
467 messages::internalError(asyncResp->res);
468 break;
469 }
470 size = *sizePtr;
471 break;
472 }
473 }
474 }
475 else if (interfaceMap.first ==
476 "xyz.openbmc_project.Time.EpochTime")
477 {
478
479 for (auto& propertyMap : interfaceMap.second)
480 {
481 if (propertyMap.first == "Elapsed")
482 {
483 const uint64_t* usecsTimeStamp =
484 std::get_if<uint64_t>(&propertyMap.second);
485 if (usecsTimeStamp == nullptr)
486 {
487 messages::internalError(asyncResp->res);
488 break;
489 }
490 timestamp =
491 static_cast<std::time_t>(*usecsTimeStamp);
492 break;
493 }
494 }
495 }
496 }
497
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500498 thisEntry["@odata.type"] = "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500499 thisEntry["@odata.id"] = dumpPath + entryID;
500 thisEntry["Id"] = entryID;
501 thisEntry["EntryType"] = "Event";
502 thisEntry["Created"] = crow::utility::getDateTime(timestamp);
503 thisEntry["Name"] = dumpType + " Dump Entry";
504
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500505 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500506
507 if (dumpType == "BMC")
508 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500509 thisEntry["DiagnosticDataType"] = "Manager";
510 thisEntry["AdditionalDataURI"] =
511 "/redfish/v1/Managers/bmc/LogServices/Dump/"
512 "attachment/" +
513 entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500514 }
515 else if (dumpType == "System")
516 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500517 thisEntry["DiagnosticDataType"] = "OEM";
518 thisEntry["OEMDiagnosticDataType"] = "System";
519 thisEntry["AdditionalDataURI"] =
520 "/redfish/v1/Systems/system/LogServices/Dump/"
521 "attachment/" +
522 entryID;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500523 }
524 }
525 asyncResp->res.jsonValue["Members@odata.count"] =
526 entriesArray.size();
527 },
528 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
529 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
530}
531
532inline void getDumpEntryById(std::shared_ptr<AsyncResp>& asyncResp,
533 const std::string& entryID,
534 const std::string& dumpType)
535{
536 std::string dumpPath;
537 if (dumpType == "BMC")
538 {
539 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
540 }
541 else if (dumpType == "System")
542 {
543 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
544 }
545 else
546 {
547 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
548 messages::internalError(asyncResp->res);
549 return;
550 }
551
552 crow::connections::systemBus->async_method_call(
553 [asyncResp, entryID, dumpPath, dumpType](
554 const boost::system::error_code ec, GetManagedObjectsType& resp) {
555 if (ec)
556 {
557 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
558 messages::internalError(asyncResp->res);
559 return;
560 }
561
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500562 bool foundDumpEntry = false;
563 std::string dumpEntryPath =
564 "/xyz/openbmc_project/dump/" +
565 std::string(boost::algorithm::to_lower_copy(dumpType)) +
566 "/entry/";
567
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500568 for (auto& objectPath : resp)
569 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500570 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500571 {
572 continue;
573 }
574
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500575 foundDumpEntry = true;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500576 std::time_t timestamp;
577 uint64_t size = 0;
578
579 for (auto& interfaceMap : objectPath.second)
580 {
581 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
582 {
583 for (auto& propertyMap : interfaceMap.second)
584 {
585 if (propertyMap.first == "Size")
586 {
587 auto sizePtr =
588 std::get_if<uint64_t>(&propertyMap.second);
589 if (sizePtr == nullptr)
590 {
591 messages::internalError(asyncResp->res);
592 break;
593 }
594 size = *sizePtr;
595 break;
596 }
597 }
598 }
599 else if (interfaceMap.first ==
600 "xyz.openbmc_project.Time.EpochTime")
601 {
602 for (auto& propertyMap : interfaceMap.second)
603 {
604 if (propertyMap.first == "Elapsed")
605 {
606 const uint64_t* usecsTimeStamp =
607 std::get_if<uint64_t>(&propertyMap.second);
608 if (usecsTimeStamp == nullptr)
609 {
610 messages::internalError(asyncResp->res);
611 break;
612 }
613 timestamp =
614 static_cast<std::time_t>(*usecsTimeStamp);
615 break;
616 }
617 }
618 }
619 }
620
621 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500622 "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500623 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
624 asyncResp->res.jsonValue["Id"] = entryID;
625 asyncResp->res.jsonValue["EntryType"] = "Event";
626 asyncResp->res.jsonValue["Created"] =
627 crow::utility::getDateTime(timestamp);
628 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
629
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500630 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500631
632 if (dumpType == "BMC")
633 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500634 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
635 asyncResp->res.jsonValue["AdditionalDataURI"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500636 "/redfish/v1/Managers/bmc/LogServices/Dump/"
637 "attachment/" +
638 entryID;
639 }
640 else if (dumpType == "System")
641 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500642 asyncResp->res.jsonValue["DiagnosticDataType"] = "OEM";
643 asyncResp->res.jsonValue["OEMDiagnosticDataType"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500644 "System";
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500645 asyncResp->res.jsonValue["AdditionalDataURI"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500646 "/redfish/v1/Systems/system/LogServices/Dump/"
647 "attachment/" +
648 entryID;
649 }
650 }
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500651 if (foundDumpEntry == false)
652 {
653 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
654 messages::internalError(asyncResp->res);
655 return;
656 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500657 },
658 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
659 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
660}
661
Stanley Chu98782562020-11-04 16:10:24 +0800662inline void deleteDumpEntry(const std::shared_ptr<AsyncResp>& asyncResp,
663 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500664 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500665{
George Liu3de8d8b2021-03-22 17:49:39 +0800666 auto respHandler = [asyncResp,
667 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500668 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
669 if (ec)
670 {
George Liu3de8d8b2021-03-22 17:49:39 +0800671 if (ec.value() == EBADR)
672 {
673 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
674 return;
675 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500676 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
677 << ec;
678 messages::internalError(asyncResp->res);
679 return;
680 }
681 };
682 crow::connections::systemBus->async_method_call(
683 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500684 "/xyz/openbmc_project/dump/" +
685 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
686 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500687 "xyz.openbmc_project.Object.Delete", "Delete");
688}
689
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500690inline void createDumpTaskCallback(const crow::Request& req,
Ed Tanousb5a76932020-09-29 16:16:58 -0700691 const std::shared_ptr<AsyncResp>& asyncResp,
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500692 const uint32_t& dumpId,
693 const std::string& dumpPath,
694 const std::string& dumpType)
695{
696 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500697 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500698 boost::system::error_code err, sdbusplus::message::message& m,
699 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000700 if (err)
701 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500702 BMCWEB_LOG_ERROR << "Error in creating a dump";
703 taskData->state = "Cancelled";
704 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000705 }
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500706 std::vector<std::pair<
707 std::string,
708 std::vector<std::pair<std::string, std::variant<std::string>>>>>
709 interfacesList;
710
711 sdbusplus::message::object_path objPath;
712
713 m.read(objPath, interfacesList);
714
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500715 if (objPath.str ==
716 "/xyz/openbmc_project/dump/" +
717 std::string(boost::algorithm::to_lower_copy(dumpType)) +
718 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500719 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500720 nlohmann::json retMessage = messages::success();
721 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500722
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500723 std::string headerLoc =
724 "Location: " + dumpPath + std::to_string(dumpId);
725 taskData->payload->httpHeaders.emplace_back(
726 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500727
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500728 taskData->state = "Completed";
729 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500730 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500731 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500732 },
733 "type='signal',interface='org.freedesktop.DBus."
734 "ObjectManager',"
735 "member='InterfacesAdded', "
736 "path='/xyz/openbmc_project/dump'");
737
738 task->startTimer(std::chrono::minutes(3));
739 task->populateResp(asyncResp->res);
740 task->payload.emplace(req);
741}
742
743inline void createDump(crow::Response& res, const crow::Request& req,
744 const std::string& dumpType)
745{
746 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
747
748 std::string dumpPath;
749 if (dumpType == "BMC")
750 {
751 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
752 }
753 else if (dumpType == "System")
754 {
755 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
756 }
757 else
758 {
759 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
760 messages::internalError(asyncResp->res);
761 return;
762 }
763
764 std::optional<std::string> diagnosticDataType;
765 std::optional<std::string> oemDiagnosticDataType;
766
767 if (!redfish::json_util::readJson(
768 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
769 "OEMDiagnosticDataType", oemDiagnosticDataType))
770 {
771 return;
772 }
773
774 if (dumpType == "System")
775 {
776 if (!oemDiagnosticDataType || !diagnosticDataType)
777 {
778 BMCWEB_LOG_ERROR << "CreateDump action parameter "
779 "'DiagnosticDataType'/"
780 "'OEMDiagnosticDataType' value not found!";
781 messages::actionParameterMissing(
782 asyncResp->res, "CollectDiagnosticData",
783 "DiagnosticDataType & OEMDiagnosticDataType");
784 return;
785 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700786 if ((*oemDiagnosticDataType != "System") ||
787 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500788 {
789 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
790 messages::invalidObject(asyncResp->res,
791 "System Dump creation parameters");
792 return;
793 }
794 }
795 else if (dumpType == "BMC")
796 {
797 if (!diagnosticDataType)
798 {
799 BMCWEB_LOG_ERROR << "CreateDump action parameter "
800 "'DiagnosticDataType' not found!";
801 messages::actionParameterMissing(
802 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
803 return;
804 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700805 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500806 {
807 BMCWEB_LOG_ERROR
808 << "Wrong parameter value passed for 'DiagnosticDataType'";
809 messages::invalidObject(asyncResp->res,
810 "BMC Dump creation parameters");
811 return;
812 }
813 }
814
815 crow::connections::systemBus->async_method_call(
816 [asyncResp, req, dumpPath, dumpType](const boost::system::error_code ec,
817 const uint32_t& dumpId) {
818 if (ec)
819 {
820 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
821 messages::internalError(asyncResp->res);
822 return;
823 }
824 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
825
826 createDumpTaskCallback(req, asyncResp, dumpId, dumpPath, dumpType);
827 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500828 "xyz.openbmc_project.Dump.Manager",
829 "/xyz/openbmc_project/dump/" +
830 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500831 "xyz.openbmc_project.Dump.Create", "CreateDump");
832}
833
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500834inline void clearDump(crow::Response& res, const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500835{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500836 std::string dumpTypeLowerCopy =
837 std::string(boost::algorithm::to_lower_copy(dumpType));
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500838 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
839 crow::connections::systemBus->async_method_call(
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500840 [asyncResp, dumpType](const boost::system::error_code ec,
841 const std::vector<std::string>& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500842 if (ec)
843 {
844 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
845 messages::internalError(asyncResp->res);
846 return;
847 }
848
849 for (const std::string& path : subTreePaths)
850 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000851 sdbusplus::message::object_path objPath(path);
852 std::string logID = objPath.filename();
853 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500854 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000855 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500856 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000857 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500858 }
859 },
860 "xyz.openbmc_project.ObjectMapper",
861 "/xyz/openbmc_project/object_mapper",
862 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500863 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
864 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
865 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500866}
867
Ed Tanous2c70f802020-09-28 14:29:23 -0700868static void parseCrashdumpParameters(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500869 const std::vector<std::pair<std::string, VariantType>>& params,
870 std::string& filename, std::string& timestamp, std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700871{
872 for (auto property : params)
873 {
874 if (property.first == "Timestamp")
875 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500876 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500877 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700878 if (value != nullptr)
879 {
880 timestamp = *value;
881 }
882 }
883 else if (property.first == "Filename")
884 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500885 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500886 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700887 if (value != nullptr)
888 {
889 filename = *value;
890 }
891 }
892 else if (property.first == "Log")
893 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500894 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500895 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700896 if (value != nullptr)
897 {
898 logfile = *value;
899 }
900 }
901 }
902}
903
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500904constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800905class SystemLogServiceCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -0700906{
907 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700908 SystemLogServiceCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800909 Node(app, "/redfish/v1/Systems/system/LogServices/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800910 {
911 entityPrivileges = {
912 {boost::beast::http::verb::get, {{"Login"}}},
913 {boost::beast::http::verb::head, {{"Login"}}},
914 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
915 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
916 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
917 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
918 }
919
920 private:
921 /**
922 * Functions triggers appropriate requests on DBus
923 */
Ed Tanouscb13a392020-07-25 19:02:03 +0000924 void doGet(crow::Response& res, const crow::Request&,
925 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800926 {
927 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800928 // Collections don't include the static data added by SubRoute because
929 // it has a duplicate entry for members
930 asyncResp->res.jsonValue["@odata.type"] =
931 "#LogServiceCollection.LogServiceCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800932 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -0800933 "/redfish/v1/Systems/system/LogServices";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800934 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
935 asyncResp->res.jsonValue["Description"] =
936 "Collection of LogServices for this Computer System";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500937 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800938 logServiceArray = nlohmann::json::array();
Ed Tanous029573d2019-02-01 10:57:49 -0800939 logServiceArray.push_back(
940 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/EventLog"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500941#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
raviteja-bc9bb6862020-02-03 11:53:32 -0600942 logServiceArray.push_back(
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500943 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/Dump"}});
raviteja-bc9bb6862020-02-03 11:53:32 -0600944#endif
945
Jason M. Billsd53dd412019-02-12 17:16:22 -0800946#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
947 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -0500948 {{"@odata.id",
949 "/redfish/v1/Systems/system/LogServices/Crashdump"}});
Jason M. Billsd53dd412019-02-12 17:16:22 -0800950#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800951 asyncResp->res.jsonValue["Members@odata.count"] =
952 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800953
954 crow::connections::systemBus->async_method_call(
955 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500956 const std::vector<std::string>& subtreePath) {
ZhikuiRena3316fc2020-01-29 14:58:08 -0800957 if (ec)
958 {
959 BMCWEB_LOG_ERROR << ec;
960 return;
961 }
962
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500963 for (auto& pathStr : subtreePath)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800964 {
965 if (pathStr.find("PostCode") != std::string::npos)
966 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000967 nlohmann::json& logServiceArrayLocal =
ZhikuiRena3316fc2020-01-29 14:58:08 -0800968 asyncResp->res.jsonValue["Members"];
Ed Tanous23a21a12020-07-25 04:45:05 +0000969 logServiceArrayLocal.push_back(
ZhikuiRena3316fc2020-01-29 14:58:08 -0800970 {{"@odata.id", "/redfish/v1/Systems/system/"
971 "LogServices/PostCodes"}});
972 asyncResp->res.jsonValue["Members@odata.count"] =
Ed Tanous23a21a12020-07-25 04:45:05 +0000973 logServiceArrayLocal.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800974 return;
975 }
976 }
977 },
978 "xyz.openbmc_project.ObjectMapper",
979 "/xyz/openbmc_project/object_mapper",
980 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500981 std::array<const char*, 1>{postCodeIface});
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800982 }
983};
984
985class EventLogService : public Node
986{
987 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700988 EventLogService(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800989 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800990 {
991 entityPrivileges = {
992 {boost::beast::http::verb::get, {{"Login"}}},
993 {boost::beast::http::verb::head, {{"Login"}}},
994 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
995 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
996 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
997 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
998 }
999
1000 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001001 void doGet(crow::Response& res, const crow::Request&,
1002 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001003 {
1004 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1005
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001006 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001007 "/redfish/v1/Systems/system/LogServices/EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001008 asyncResp->res.jsonValue["@odata.type"] =
1009 "#LogService.v1_1_0.LogService";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001010 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1011 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
Gunnar Mills73ec8302020-04-14 16:02:42 -05001012 asyncResp->res.jsonValue["Id"] = "EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001013 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
1014 asyncResp->res.jsonValue["Entries"] = {
1015 {"@odata.id",
Ed Tanous029573d2019-02-01 10:57:49 -08001016 "/redfish/v1/Systems/system/LogServices/EventLog/Entries"}};
Gunnar Millse7d6c8b2019-07-03 11:30:01 -05001017 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1018
1019 {"target", "/redfish/v1/Systems/system/LogServices/EventLog/"
1020 "Actions/LogService.ClearLog"}};
Jason M. Bills489640c2019-05-17 09:56:36 -07001021 }
1022};
1023
Tim Lee1f56a3a2019-10-09 10:17:57 +08001024class JournalEventLogClear : public Node
Jason M. Bills489640c2019-05-17 09:56:36 -07001025{
1026 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001027 JournalEventLogClear(App& app) :
Jason M. Bills489640c2019-05-17 09:56:36 -07001028 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
1029 "LogService.ClearLog/")
1030 {
1031 entityPrivileges = {
1032 {boost::beast::http::verb::get, {{"Login"}}},
1033 {boost::beast::http::verb::head, {{"Login"}}},
1034 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1035 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1036 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1037 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1038 }
1039
1040 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001041 void doPost(crow::Response& res, const crow::Request&,
1042 const std::vector<std::string>&) override
Jason M. Bills489640c2019-05-17 09:56:36 -07001043 {
1044 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1045
1046 // Clear the EventLog by deleting the log files
1047 std::vector<std::filesystem::path> redfishLogFiles;
1048 if (getRedfishLogFiles(redfishLogFiles))
1049 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001050 for (const std::filesystem::path& file : redfishLogFiles)
Jason M. Bills489640c2019-05-17 09:56:36 -07001051 {
1052 std::error_code ec;
1053 std::filesystem::remove(file, ec);
1054 }
1055 }
1056
1057 // Reload rsyslog so it knows to start new log files
1058 crow::connections::systemBus->async_method_call(
1059 [asyncResp](const boost::system::error_code ec) {
1060 if (ec)
1061 {
1062 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1063 messages::internalError(asyncResp->res);
1064 return;
1065 }
1066
1067 messages::success(asyncResp->res);
1068 },
1069 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1070 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1071 "replace");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001072 }
1073};
1074
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001075static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001076 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001077 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001078{
Jason M. Bills95820182019-04-22 16:25:34 -07001079 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001080 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001081 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001082 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001083 {
1084 return 1;
1085 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001086 std::string timestamp = logEntry.substr(0, space);
1087 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001088 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001089 if (entryStart == std::string::npos)
1090 {
1091 return 1;
1092 }
1093 std::string_view entry(logEntry);
1094 entry.remove_prefix(entryStart);
1095 // Use split to separate the entry into its fields
1096 std::vector<std::string> logEntryFields;
1097 boost::split(logEntryFields, entry, boost::is_any_of(","),
1098 boost::token_compress_on);
1099 // We need at least a MessageId to be valid
1100 if (logEntryFields.size() < 1)
1101 {
1102 return 1;
1103 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001104 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001105
Jason M. Bills4851d452019-03-28 11:27:48 -07001106 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001107 const message_registries::Message* message =
Jason M. Bills4851d452019-03-28 11:27:48 -07001108 message_registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001109
Jason M. Bills4851d452019-03-28 11:27:48 -07001110 std::string msg;
1111 std::string severity;
1112 if (message != nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001113 {
Jason M. Bills4851d452019-03-28 11:27:48 -07001114 msg = message->message;
1115 severity = message->severity;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001116 }
1117
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001118 // Get the MessageArgs from the log if there are any
1119 boost::beast::span<std::string> messageArgs;
1120 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001121 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001122 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001123 // If the first string is empty, assume there are no MessageArgs
1124 std::size_t messageArgsSize = 0;
1125 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001126 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001127 messageArgsSize = logEntryFields.size() - 1;
1128 }
1129
Ed Tanous23a21a12020-07-25 04:45:05 +00001130 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001131
1132 // Fill the MessageArgs into the Message
1133 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001134 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001135 {
1136 std::string argStr = "%" + std::to_string(++i);
1137 size_t argPos = msg.find(argStr);
1138 if (argPos != std::string::npos)
1139 {
1140 msg.replace(argPos, argStr.length(), messageArg);
1141 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001142 }
1143 }
1144
Jason M. Bills95820182019-04-22 16:25:34 -07001145 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1146 // format which matches the Redfish format except for the fractional seconds
1147 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001148 std::size_t dot = timestamp.find_first_of('.');
1149 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001150 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001151 {
Jason M. Bills95820182019-04-22 16:25:34 -07001152 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001153 }
1154
1155 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001156 logEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001157 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001158 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001159 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001160 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001161 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001162 {"Id", logEntryID},
1163 {"Message", std::move(msg)},
1164 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001165 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001166 {"EntryType", "Event"},
Jason M. Bills95820182019-04-22 16:25:34 -07001167 {"Severity", std::move(severity)},
1168 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001169 return 0;
1170}
1171
Anthony Wilson27062602019-04-22 02:10:09 -05001172class JournalEventLogEntryCollection : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001173{
1174 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001175 JournalEventLogEntryCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -08001176 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001177 {
1178 entityPrivileges = {
1179 {boost::beast::http::verb::get, {{"Login"}}},
1180 {boost::beast::http::verb::head, {{"Login"}}},
1181 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1182 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1183 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1184 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1185 }
1186
1187 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001188 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00001189 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001190 {
1191 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous271584a2019-07-09 16:24:22 -07001192 uint64_t skip = 0;
1193 uint64_t top = maxEntriesPerPage; // Show max entries by default
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001194 if (!getSkipParam(asyncResp->res, req, skip))
1195 {
1196 return;
1197 }
1198 if (!getTopParam(asyncResp->res, req, top))
1199 {
1200 return;
1201 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001202 // Collections don't include the static data added by SubRoute because
1203 // it has a duplicate entry for members
1204 asyncResp->res.jsonValue["@odata.type"] =
1205 "#LogEntryCollection.LogEntryCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001206 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001207 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001208 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1209 asyncResp->res.jsonValue["Description"] =
1210 "Collection of System Event Log Entries";
Andrew Geisslercb92c032018-08-17 07:56:14 -07001211
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001212 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001213 logEntryArray = nlohmann::json::array();
Jason M. Bills95820182019-04-22 16:25:34 -07001214 // Go through the log files and create a unique ID for each entry
1215 std::vector<std::filesystem::path> redfishLogFiles;
1216 getRedfishLogFiles(redfishLogFiles);
Ed Tanousb01bf292019-03-25 19:25:26 +00001217 uint64_t entryCount = 0;
Jason M. Billscd225da2019-05-08 15:31:57 -07001218 std::string logEntry;
Jason M. Bills95820182019-04-22 16:25:34 -07001219
1220 // Oldest logs are in the last file, so start there and loop backwards
Jason M. Billscd225da2019-05-08 15:31:57 -07001221 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1222 it++)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001223 {
Jason M. Billscd225da2019-05-08 15:31:57 -07001224 std::ifstream logStream(*it);
Jason M. Bills95820182019-04-22 16:25:34 -07001225 if (!logStream.is_open())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001226 {
1227 continue;
1228 }
1229
Jason M. Billse85d6b12019-07-29 17:01:15 -07001230 // Reset the unique ID on the first entry
1231 bool firstEntry = true;
Jason M. Bills95820182019-04-22 16:25:34 -07001232 while (std::getline(logStream, logEntry))
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001233 {
Jason M. Bills95820182019-04-22 16:25:34 -07001234 entryCount++;
1235 // Handle paging using skip (number of entries to skip from the
1236 // start) and top (number of entries to display)
1237 if (entryCount <= skip || entryCount > skip + top)
1238 {
1239 continue;
1240 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001241
Jason M. Bills95820182019-04-22 16:25:34 -07001242 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07001243 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills95820182019-04-22 16:25:34 -07001244 {
1245 continue;
1246 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001247
Jason M. Billse85d6b12019-07-29 17:01:15 -07001248 if (firstEntry)
1249 {
1250 firstEntry = false;
1251 }
1252
Jason M. Bills95820182019-04-22 16:25:34 -07001253 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001254 nlohmann::json& bmcLogEntry = logEntryArray.back();
Jason M. Bills95820182019-04-22 16:25:34 -07001255 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1256 {
1257 messages::internalError(asyncResp->res);
1258 return;
1259 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001260 }
1261 }
1262 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1263 if (skip + top < entryCount)
1264 {
1265 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Bills95820182019-04-22 16:25:34 -07001266 "/redfish/v1/Systems/system/LogServices/EventLog/"
1267 "Entries?$skip=" +
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001268 std::to_string(skip + top);
1269 }
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001270 }
1271};
1272
Jason M. Bills897967d2019-07-29 17:05:30 -07001273class JournalEventLogEntry : public Node
1274{
1275 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001276 JournalEventLogEntry(App& app) :
Jason M. Bills897967d2019-07-29 17:05:30 -07001277 Node(app,
1278 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1279 std::string())
1280 {
1281 entityPrivileges = {
1282 {boost::beast::http::verb::get, {{"Login"}}},
1283 {boost::beast::http::verb::head, {{"Login"}}},
1284 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1285 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1286 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1287 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1288 }
1289
1290 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001291 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001292 const std::vector<std::string>& params) override
Jason M. Bills897967d2019-07-29 17:05:30 -07001293 {
1294 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1295 if (params.size() != 1)
1296 {
1297 messages::internalError(asyncResp->res);
1298 return;
1299 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001300 const std::string& targetID = params[0];
Jason M. Bills897967d2019-07-29 17:05:30 -07001301
1302 // Go through the log files and check the unique ID for each entry to
1303 // find the target entry
1304 std::vector<std::filesystem::path> redfishLogFiles;
1305 getRedfishLogFiles(redfishLogFiles);
1306 std::string logEntry;
1307
1308 // Oldest logs are in the last file, so start there and loop backwards
1309 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1310 it++)
1311 {
1312 std::ifstream logStream(*it);
1313 if (!logStream.is_open())
1314 {
1315 continue;
1316 }
1317
1318 // Reset the unique ID on the first entry
1319 bool firstEntry = true;
1320 while (std::getline(logStream, logEntry))
1321 {
1322 std::string idStr;
1323 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1324 {
1325 continue;
1326 }
1327
1328 if (firstEntry)
1329 {
1330 firstEntry = false;
1331 }
1332
1333 if (idStr == targetID)
1334 {
1335 if (fillEventLogEntryJson(idStr, logEntry,
1336 asyncResp->res.jsonValue) != 0)
1337 {
1338 messages::internalError(asyncResp->res);
1339 return;
1340 }
1341 return;
1342 }
1343 }
1344 }
1345 // Requested ID was not found
1346 messages::resourceMissingAtURI(asyncResp->res, targetID);
1347 }
1348};
1349
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001350class DBusEventLogEntryCollection : public Node
1351{
1352 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001353 DBusEventLogEntryCollection(App& app) :
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001354 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
1355 {
1356 entityPrivileges = {
1357 {boost::beast::http::verb::get, {{"Login"}}},
1358 {boost::beast::http::verb::head, {{"Login"}}},
1359 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1360 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1361 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1362 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1363 }
1364
1365 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001366 void doGet(crow::Response& res, const crow::Request&,
1367 const std::vector<std::string>&) override
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001368 {
1369 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1370
1371 // Collections don't include the static data added by SubRoute because
1372 // it has a duplicate entry for members
1373 asyncResp->res.jsonValue["@odata.type"] =
1374 "#LogEntryCollection.LogEntryCollection";
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001375 asyncResp->res.jsonValue["@odata.id"] =
1376 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1377 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1378 asyncResp->res.jsonValue["Description"] =
1379 "Collection of System Event Log Entries";
1380
Andrew Geisslercb92c032018-08-17 07:56:14 -07001381 // DBus implementation of EventLog/Entries
1382 // Make call to Logging Service to find all log entry objects
1383 crow::connections::systemBus->async_method_call(
1384 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001385 GetManagedObjectsType& resp) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001386 if (ec)
1387 {
1388 // TODO Handle for specific error code
1389 BMCWEB_LOG_ERROR
1390 << "getLogEntriesIfaceData resp_handler got error "
1391 << ec;
1392 messages::internalError(asyncResp->res);
1393 return;
1394 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001395 nlohmann::json& entriesArray =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001396 asyncResp->res.jsonValue["Members"];
1397 entriesArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001398 for (auto& objectPath : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001399 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001400 uint32_t* id = nullptr;
1401 std::time_t timestamp{};
1402 std::time_t updateTimestamp{};
1403 std::string* severity = nullptr;
1404 std::string* message = nullptr;
1405 std::string* filePath = nullptr;
1406 bool resolved = false;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001407 for (auto& interfaceMap : objectPath.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001408 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001409 if (interfaceMap.first ==
Andrew Geisslercb92c032018-08-17 07:56:14 -07001410 "xyz.openbmc_project.Logging.Entry")
1411 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001412 for (auto& propertyMap : interfaceMap.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001413 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001414 if (propertyMap.first == "Id")
George Liuebd45902020-08-26 14:21:10 +08001415 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001416 id = std::get_if<uint32_t>(
1417 &propertyMap.second);
George Liuebd45902020-08-26 14:21:10 +08001418 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001419 else if (propertyMap.first == "Timestamp")
George Liuebd45902020-08-26 14:21:10 +08001420 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001421 const uint64_t* millisTimeStamp =
1422 std::get_if<uint64_t>(
1423 &propertyMap.second);
1424 if (millisTimeStamp != nullptr)
1425 {
1426 timestamp = crow::utility::getTimestamp(
George Liuebd45902020-08-26 14:21:10 +08001427 *millisTimeStamp);
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001428 }
George Liuebd45902020-08-26 14:21:10 +08001429 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001430 else if (propertyMap.first == "UpdateTimestamp")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001431 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001432 const uint64_t* millisTimeStamp =
1433 std::get_if<uint64_t>(
1434 &propertyMap.second);
1435 if (millisTimeStamp != nullptr)
1436 {
1437 updateTimestamp =
1438 crow::utility::getTimestamp(
1439 *millisTimeStamp);
1440 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001441 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001442 else if (propertyMap.first == "Severity")
1443 {
1444 severity = std::get_if<std::string>(
1445 &propertyMap.second);
1446 }
1447 else if (propertyMap.first == "Message")
1448 {
1449 message = std::get_if<std::string>(
1450 &propertyMap.second);
1451 }
1452 else if (propertyMap.first == "Resolved")
1453 {
1454 bool* resolveptr =
1455 std::get_if<bool>(&propertyMap.second);
1456 if (resolveptr == nullptr)
1457 {
1458 messages::internalError(asyncResp->res);
1459 return;
1460 }
1461 resolved = *resolveptr;
1462 }
1463 }
1464 if (id == nullptr || message == nullptr ||
1465 severity == nullptr)
1466 {
1467 messages::internalError(asyncResp->res);
1468 return;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001469 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001470 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001471 else if (interfaceMap.first ==
1472 "xyz.openbmc_project.Common.FilePath")
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001473 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001474 for (auto& propertyMap : interfaceMap.second)
1475 {
1476 if (propertyMap.first == "Path")
1477 {
1478 filePath = std::get_if<std::string>(
1479 &propertyMap.second);
1480 }
1481 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001482 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001483 }
1484 // Object path without the xyz.openbmc_project.Logging.Entry
1485 // interface, ignore and continue.
1486 if (id == nullptr || message == nullptr ||
1487 severity == nullptr)
1488 {
1489 continue;
1490 }
1491 entriesArray.push_back({});
1492 nlohmann::json& thisEntry = entriesArray.back();
1493 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1494 thisEntry["@odata.id"] = "/redfish/v1/Systems/system/"
1495 "LogServices/EventLog/Entries/" +
1496 std::to_string(*id);
1497 thisEntry["Name"] = "System Event Log Entry";
1498 thisEntry["Id"] = std::to_string(*id);
1499 thisEntry["Message"] = *message;
1500 thisEntry["Resolved"] = resolved;
1501 thisEntry["EntryType"] = "Event";
1502 thisEntry["Severity"] =
1503 translateSeverityDbusToRedfish(*severity);
1504 thisEntry["Created"] =
1505 crow::utility::getDateTime(timestamp);
1506 thisEntry["Modified"] =
1507 crow::utility::getDateTime(updateTimestamp);
1508 if (filePath != nullptr)
1509 {
1510 thisEntry["AdditionalDataURI"] =
1511 "/redfish/v1/Systems/system/LogServices/EventLog/"
1512 "attachment/" +
1513 std::to_string(*id);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001514 }
1515 }
1516 std::sort(entriesArray.begin(), entriesArray.end(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001517 [](const nlohmann::json& left,
1518 const nlohmann::json& right) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001519 return (left["Id"] <= right["Id"]);
1520 });
1521 asyncResp->res.jsonValue["Members@odata.count"] =
1522 entriesArray.size();
1523 },
1524 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1525 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001526 }
1527};
1528
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001529class DBusEventLogEntry : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001530{
1531 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001532 DBusEventLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001533 Node(app,
Ed Tanous029573d2019-02-01 10:57:49 -08001534 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1535 std::string())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001536 {
1537 entityPrivileges = {
1538 {boost::beast::http::verb::get, {{"Login"}}},
1539 {boost::beast::http::verb::head, {{"Login"}}},
1540 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1541 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1542 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1543 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1544 }
1545
1546 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001547 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001548 const std::vector<std::string>& params) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001549 {
1550 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous029573d2019-02-01 10:57:49 -08001551 if (params.size() != 1)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001552 {
1553 messages::internalError(asyncResp->res);
1554 return;
1555 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001556 std::string entryID = params[0];
1557 dbus::utility::escapePathForDbus(entryID);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001558
Andrew Geisslercb92c032018-08-17 07:56:14 -07001559 // DBus implementation of EventLog/Entries
1560 // Make call to Logging Service to find all log entry objects
1561 crow::connections::systemBus->async_method_call(
1562 [asyncResp, entryID](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001563 GetManagedPropertyType& resp) {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001564 if (ec.value() == EBADR)
1565 {
1566 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1567 entryID);
1568 return;
1569 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001570 if (ec)
1571 {
1572 BMCWEB_LOG_ERROR
1573 << "EventLogEntry (DBus) resp_handler got error " << ec;
1574 messages::internalError(asyncResp->res);
1575 return;
1576 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001577 uint32_t* id = nullptr;
Ed Tanous66664f22019-10-11 13:05:49 -07001578 std::time_t timestamp{};
George Liud139c232020-08-18 18:48:57 +08001579 std::time_t updateTimestamp{};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001580 std::string* severity = nullptr;
1581 std::string* message = nullptr;
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001582 std::string* filePath = nullptr;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001583 bool resolved = false;
George Liud139c232020-08-18 18:48:57 +08001584
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001585 for (auto& propertyMap : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001586 {
1587 if (propertyMap.first == "Id")
1588 {
1589 id = std::get_if<uint32_t>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001590 }
1591 else if (propertyMap.first == "Timestamp")
1592 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001593 const uint64_t* millisTimeStamp =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001594 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001595 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001596 {
1597 timestamp =
1598 crow::utility::getTimestamp(*millisTimeStamp);
1599 }
George Liud139c232020-08-18 18:48:57 +08001600 }
1601 else if (propertyMap.first == "UpdateTimestamp")
1602 {
1603 const uint64_t* millisTimeStamp =
1604 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001605 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001606 {
1607 updateTimestamp =
1608 crow::utility::getTimestamp(*millisTimeStamp);
1609 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001610 }
1611 else if (propertyMap.first == "Severity")
1612 {
1613 severity =
1614 std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001615 }
1616 else if (propertyMap.first == "Message")
1617 {
1618 message = std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001619 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001620 else if (propertyMap.first == "Resolved")
1621 {
1622 bool* resolveptr =
1623 std::get_if<bool>(&propertyMap.second);
1624 if (resolveptr == nullptr)
1625 {
1626 messages::internalError(asyncResp->res);
1627 return;
1628 }
1629 resolved = *resolveptr;
1630 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001631 else if (propertyMap.first == "Path")
1632 {
1633 filePath =
1634 std::get_if<std::string>(&propertyMap.second);
1635 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001636 }
Ed Tanous271584a2019-07-09 16:24:22 -07001637 if (id == nullptr || message == nullptr || severity == nullptr)
1638 {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001639 messages::internalError(asyncResp->res);
Ed Tanous271584a2019-07-09 16:24:22 -07001640 return;
1641 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001642 asyncResp->res.jsonValue["@odata.type"] =
1643 "#LogEntry.v1_8_0.LogEntry";
1644 asyncResp->res.jsonValue["@odata.id"] =
1645 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1646 std::to_string(*id);
1647 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1648 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1649 asyncResp->res.jsonValue["Message"] = *message;
1650 asyncResp->res.jsonValue["Resolved"] = resolved;
1651 asyncResp->res.jsonValue["EntryType"] = "Event";
1652 asyncResp->res.jsonValue["Severity"] =
1653 translateSeverityDbusToRedfish(*severity);
1654 asyncResp->res.jsonValue["Created"] =
1655 crow::utility::getDateTime(timestamp);
1656 asyncResp->res.jsonValue["Modified"] =
1657 crow::utility::getDateTime(updateTimestamp);
1658 if (filePath != nullptr)
1659 {
1660 asyncResp->res.jsonValue["AdditionalDataURI"] =
1661 "/redfish/v1/Systems/system/LogServices/EventLog/"
1662 "attachment/" +
1663 std::to_string(*id);
1664 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001665 },
1666 "xyz.openbmc_project.Logging",
1667 "/xyz/openbmc_project/logging/entry/" + entryID,
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001668 "org.freedesktop.DBus.Properties", "GetAll", "");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001669 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001670
Xiaochao Ma75710de2021-01-21 17:56:02 +08001671 void doPatch(crow::Response& res, const crow::Request& req,
1672 const std::vector<std::string>& params) override
1673 {
1674 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1675
1676 if (params.size() != 1)
1677 {
1678 messages::internalError(asyncResp->res);
1679 return;
1680 }
1681 std::string entryId = params[0];
1682
1683 std::optional<bool> resolved;
1684
1685 if (!json_util::readJson(req, res, "Resolved", resolved))
1686 {
1687 return;
1688 }
1689
1690 if (resolved)
1691 {
1692 BMCWEB_LOG_DEBUG << "Set Resolved";
1693
1694 crow::connections::systemBus->async_method_call(
1695 [asyncResp, resolved,
1696 entryId](const boost::system::error_code ec) {
1697 if (ec)
1698 {
1699 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1700 messages::internalError(asyncResp->res);
1701 return;
1702 }
1703 },
1704 "xyz.openbmc_project.Logging",
1705 "/xyz/openbmc_project/logging/entry/" + entryId,
1706 "org.freedesktop.DBus.Properties", "Set",
1707 "xyz.openbmc_project.Logging.Entry", "Resolved",
1708 std::variant<bool>(*resolved));
1709 }
1710 }
1711
Ed Tanouscb13a392020-07-25 19:02:03 +00001712 void doDelete(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001713 const std::vector<std::string>& params) override
Chicago Duan336e96c2019-07-15 14:22:08 +08001714 {
1715
1716 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1717
1718 auto asyncResp = std::make_shared<AsyncResp>(res);
1719
1720 if (params.size() != 1)
1721 {
1722 messages::internalError(asyncResp->res);
1723 return;
1724 }
1725 std::string entryID = params[0];
1726
1727 dbus::utility::escapePathForDbus(entryID);
1728
1729 // Process response from Logging service.
George Liu3de8d8b2021-03-22 17:49:39 +08001730 auto respHandler = [asyncResp,
1731 entryID](const boost::system::error_code ec) {
Chicago Duan336e96c2019-07-15 14:22:08 +08001732 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1733 if (ec)
1734 {
George Liu3de8d8b2021-03-22 17:49:39 +08001735 if (ec.value() == EBADR)
1736 {
1737 messages::resourceNotFound(asyncResp->res, "LogEntry",
1738 entryID);
1739 return;
1740 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001741 // TODO Handle for specific error code
1742 BMCWEB_LOG_ERROR
1743 << "EventLogEntry (DBus) doDelete respHandler got error "
1744 << ec;
1745 asyncResp->res.result(
1746 boost::beast::http::status::internal_server_error);
1747 return;
1748 }
1749
1750 asyncResp->res.result(boost::beast::http::status::ok);
1751 };
1752
1753 // Make call to Logging service to request Delete Log
1754 crow::connections::systemBus->async_method_call(
1755 respHandler, "xyz.openbmc_project.Logging",
1756 "/xyz/openbmc_project/logging/entry/" + entryID,
1757 "xyz.openbmc_project.Object.Delete", "Delete");
1758 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001759};
1760
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001761class DBusEventLogEntryDownload : public Node
1762{
1763 public:
1764 DBusEventLogEntryDownload(App& app) :
1765 Node(
1766 app,
1767 "/redfish/v1/Systems/system/LogServices/EventLog/attachment/<str>/",
1768 std::string())
1769 {
1770 entityPrivileges = {
1771 {boost::beast::http::verb::get, {{"Login"}}},
1772 {boost::beast::http::verb::head, {{"Login"}}},
1773 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1774 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1775 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1776 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1777 }
1778
1779 private:
1780 void doGet(crow::Response& res, const crow::Request& req,
1781 const std::vector<std::string>& params) override
1782 {
1783 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1784 if (params.size() != 1)
1785 {
1786 messages::internalError(asyncResp->res);
1787 return;
1788 }
1789
1790 std::string_view acceptHeader = req.getHeaderValue("Accept");
1791 // The iterators in boost/http/rfc7230.hpp end the string if '/' is
1792 // found, so replace it with arbitrary character '|' which is not part
1793 // of the Accept header syntax.
1794 std::string acceptStr =
1795 boost::replace_all_copy(std::string(acceptHeader), "/", "|");
1796 boost::beast::http::ext_list acceptTypes{acceptStr};
1797 bool supported = false;
1798 for (const auto& type : acceptTypes)
1799 {
1800 if ((type.first == "*|*") ||
1801 (type.first == "application|octet-stream"))
1802 {
1803 supported = true;
1804 break;
1805 }
1806 }
1807 if (!supported)
1808 {
1809 asyncResp->res.result(boost::beast::http::status::bad_request);
1810 return;
1811 }
1812
1813 std::string entryID = params[0];
1814 dbus::utility::escapePathForDbus(entryID);
1815
1816 crow::connections::systemBus->async_method_call(
1817 [asyncResp, entryID](const boost::system::error_code ec,
1818 const sdbusplus::message::unix_fd& unixfd) {
1819 if (ec.value() == EBADR)
1820 {
1821 messages::resourceNotFound(asyncResp->res,
1822 "EventLogAttachment", entryID);
1823 return;
1824 }
1825 if (ec)
1826 {
1827 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1828 messages::internalError(asyncResp->res);
1829 return;
1830 }
1831
1832 int fd = -1;
1833 fd = dup(unixfd);
1834 if (fd == -1)
1835 {
1836 messages::internalError(asyncResp->res);
1837 return;
1838 }
1839
1840 long long int size = lseek(fd, 0, SEEK_END);
1841 if (size == -1)
1842 {
1843 messages::internalError(asyncResp->res);
1844 return;
1845 }
1846
1847 // Arbitrary max size of 64kb
1848 constexpr int maxFileSize = 65536;
1849 if (size > maxFileSize)
1850 {
1851 BMCWEB_LOG_ERROR
1852 << "File size exceeds maximum allowed size of "
1853 << maxFileSize;
1854 messages::internalError(asyncResp->res);
1855 return;
1856 }
1857 std::vector<char> data(static_cast<size_t>(size));
1858 long long int rc = lseek(fd, 0, SEEK_SET);
1859 if (rc == -1)
1860 {
1861 messages::internalError(asyncResp->res);
1862 return;
1863 }
1864 rc = read(fd, data.data(), data.size());
1865 if ((rc == -1) || (rc != size))
1866 {
1867 messages::internalError(asyncResp->res);
1868 return;
1869 }
1870 close(fd);
1871
1872 std::string_view strData(data.data(), data.size());
1873 std::string output = crow::utility::base64encode(strData);
1874
1875 asyncResp->res.addHeader("Content-Type",
1876 "application/octet-stream");
1877 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1878 asyncResp->res.body() = std::move(output);
1879 },
1880 "xyz.openbmc_project.Logging",
1881 "/xyz/openbmc_project/logging/entry/" + entryID,
1882 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1883 }
1884};
1885
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001886class BMCLogServiceCollection : public Node
1887{
1888 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001889 BMCLogServiceCollection(App& app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -07001890 Node(app, "/redfish/v1/Managers/bmc/LogServices/")
Ed Tanous1da66f72018-07-27 16:13:37 -07001891 {
Ed Tanous1da66f72018-07-27 16:13:37 -07001892 entityPrivileges = {
Jason M. Billse1f26342018-07-18 12:12:00 -07001893 {boost::beast::http::verb::get, {{"Login"}}},
1894 {boost::beast::http::verb::head, {{"Login"}}},
1895 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1896 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1897 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1898 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07001899 }
1900
1901 private:
1902 /**
1903 * Functions triggers appropriate requests on DBus
1904 */
Ed Tanouscb13a392020-07-25 19:02:03 +00001905 void doGet(crow::Response& res, const crow::Request&,
1906 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07001907 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001908 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07001909 // Collections don't include the static data added by SubRoute because
1910 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07001911 asyncResp->res.jsonValue["@odata.type"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001912 "#LogServiceCollection.LogServiceCollection";
Jason M. Billse1f26342018-07-18 12:12:00 -07001913 asyncResp->res.jsonValue["@odata.id"] =
1914 "/redfish/v1/Managers/bmc/LogServices";
1915 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
1916 asyncResp->res.jsonValue["Description"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001917 "Collection of LogServices for this Manager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001918 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001919 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001920#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
1921 logServiceArray.push_back(
1922 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
1923#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001924#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
1925 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001926 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001927#endif
Jason M. Billse1f26342018-07-18 12:12:00 -07001928 asyncResp->res.jsonValue["Members@odata.count"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001929 logServiceArray.size();
Ed Tanous1da66f72018-07-27 16:13:37 -07001930 }
1931};
1932
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001933class BMCJournalLogService : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07001934{
1935 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001936 BMCJournalLogService(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001937 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Jason M. Billse1f26342018-07-18 12:12:00 -07001938 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001939 entityPrivileges = {
1940 {boost::beast::http::verb::get, {{"Login"}}},
1941 {boost::beast::http::verb::head, {{"Login"}}},
1942 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1943 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1944 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1945 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1946 }
1947
1948 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00001949 void doGet(crow::Response& res, const crow::Request&,
1950 const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07001951 {
1952 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Billse1f26342018-07-18 12:12:00 -07001953 asyncResp->res.jsonValue["@odata.type"] =
1954 "#LogService.v1_1_0.LogService";
Ed Tanous0f74e642018-11-12 15:17:05 -08001955 asyncResp->res.jsonValue["@odata.id"] =
1956 "/redfish/v1/Managers/bmc/LogServices/Journal";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001957 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
1958 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
1959 asyncResp->res.jsonValue["Id"] = "BMC Journal";
Jason M. Billse1f26342018-07-18 12:12:00 -07001960 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Jason M. Billscd50aa42019-02-12 17:09:02 -08001961 asyncResp->res.jsonValue["Entries"] = {
1962 {"@odata.id",
Ed Tanous086be232019-05-23 11:47:09 -07001963 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07001964 }
1965};
1966
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001967static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
1968 sd_journal* journal,
1969 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07001970{
1971 // Get the Log Entry contents
1972 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07001973
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001974 std::string message;
1975 std::string_view syslogID;
1976 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
1977 if (ret < 0)
1978 {
1979 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
1980 << strerror(-ret);
1981 }
1982 if (!syslogID.empty())
1983 {
1984 message += std::string(syslogID) + ": ";
1985 }
1986
Ed Tanous39e77502019-03-04 17:35:53 -08001987 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07001988 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001989 if (ret < 0)
1990 {
1991 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
1992 return 1;
1993 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001994 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001995
1996 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07001997 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07001998 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07001999 if (ret < 0)
2000 {
2001 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07002002 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002003
2004 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002005 std::string entryTimeStr;
2006 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002007 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002008 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002009 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002010
2011 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002012 bmcJournalLogEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07002013 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002014 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2015 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002016 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002017 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002018 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002019 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002020 {"Severity", severity <= 2 ? "Critical"
2021 : severity <= 4 ? "Warning"
2022 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002023 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002024 {"Created", std::move(entryTimeStr)}};
2025 return 0;
2026}
2027
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002028class BMCJournalLogEntryCollection : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002029{
2030 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002031 BMCJournalLogEntryCollection(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002032 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Jason M. Billse1f26342018-07-18 12:12:00 -07002033 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002034 entityPrivileges = {
2035 {boost::beast::http::verb::get, {{"Login"}}},
2036 {boost::beast::http::verb::head, {{"Login"}}},
2037 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2038 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2039 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2040 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2041 }
2042
2043 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002044 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002045 const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07002046 {
2047 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002048 static constexpr const long maxEntriesPerPage = 1000;
Ed Tanous271584a2019-07-09 16:24:22 -07002049 uint64_t skip = 0;
2050 uint64_t top = maxEntriesPerPage; // Show max entries by default
Jason M. Bills16428a12018-11-02 12:42:29 -07002051 if (!getSkipParam(asyncResp->res, req, skip))
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002052 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002053 return;
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002054 }
Jason M. Bills16428a12018-11-02 12:42:29 -07002055 if (!getTopParam(asyncResp->res, req, top))
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002056 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002057 return;
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002058 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002059 // Collections don't include the static data added by SubRoute because
2060 // it has a duplicate entry for members
2061 asyncResp->res.jsonValue["@odata.type"] =
2062 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002063 asyncResp->res.jsonValue["@odata.id"] =
2064 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002065 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002066 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002067 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2068 asyncResp->res.jsonValue["Description"] =
2069 "Collection of BMC Journal Entries";
Ed Tanous0f74e642018-11-12 15:17:05 -08002070 asyncResp->res.jsonValue["@odata.id"] =
2071 "/redfish/v1/Managers/bmc/LogServices/BmcLog/Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002072 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07002073 logEntryArray = nlohmann::json::array();
2074
2075 // Go through the journal and use the timestamp to create a unique ID
2076 // for each entry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002077 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07002078 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2079 if (ret < 0)
2080 {
2081 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07002082 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002083 return;
2084 }
2085 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2086 journalTmp, sd_journal_close);
2087 journalTmp = nullptr;
Ed Tanousb01bf292019-03-25 19:25:26 +00002088 uint64_t entryCount = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -07002089 // Reset the unique ID on the first entry
2090 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07002091 SD_JOURNAL_FOREACH(journal.get())
2092 {
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002093 entryCount++;
2094 // Handle paging using skip (number of entries to skip from the
2095 // start) and top (number of entries to display)
2096 if (entryCount <= skip || entryCount > skip + top)
2097 {
2098 continue;
2099 }
2100
Jason M. Bills16428a12018-11-02 12:42:29 -07002101 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07002102 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
Jason M. Billse1f26342018-07-18 12:12:00 -07002103 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002104 continue;
2105 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002106
Jason M. Billse85d6b12019-07-29 17:01:15 -07002107 if (firstEntry)
2108 {
2109 firstEntry = false;
2110 }
2111
Jason M. Billse1f26342018-07-18 12:12:00 -07002112 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002113 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002114 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2115 bmcJournalLogEntry) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07002116 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002117 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002118 return;
2119 }
2120 }
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002121 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2122 if (skip + top < entryCount)
2123 {
2124 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002125 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002126 std::to_string(skip + top);
2127 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002128 }
2129};
2130
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002131class BMCJournalLogEntry : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002132{
2133 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002134 BMCJournalLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002135 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/",
Jason M. Billse1f26342018-07-18 12:12:00 -07002136 std::string())
2137 {
2138 entityPrivileges = {
2139 {boost::beast::http::verb::get, {{"Login"}}},
2140 {boost::beast::http::verb::head, {{"Login"}}},
2141 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2142 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2143 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2144 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2145 }
2146
2147 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002148 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002149 const std::vector<std::string>& params) override
Jason M. Billse1f26342018-07-18 12:12:00 -07002150 {
2151 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2152 if (params.size() != 1)
2153 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002154 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002155 return;
2156 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002157 const std::string& entryID = params[0];
Jason M. Billse1f26342018-07-18 12:12:00 -07002158 // Convert the unique ID back to a timestamp to find the entry
Jason M. Billse1f26342018-07-18 12:12:00 -07002159 uint64_t ts = 0;
Ed Tanous271584a2019-07-09 16:24:22 -07002160 uint64_t index = 0;
Jason M. Bills16428a12018-11-02 12:42:29 -07002161 if (!getTimestampFromID(asyncResp->res, entryID, ts, index))
Jason M. Billse1f26342018-07-18 12:12:00 -07002162 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002163 return;
Jason M. Billse1f26342018-07-18 12:12:00 -07002164 }
2165
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002166 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07002167 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2168 if (ret < 0)
2169 {
2170 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07002171 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002172 return;
2173 }
2174 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2175 journalTmp, sd_journal_close);
2176 journalTmp = nullptr;
2177 // Go to the timestamp in the log and move to the entry at the index
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002178 // tracking the unique ID
2179 std::string idStr;
2180 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07002181 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
Manojkiran Eda2056b6d2020-05-28 08:57:36 +05302182 if (ret < 0)
2183 {
2184 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2185 << strerror(-ret);
2186 messages::internalError(asyncResp->res);
2187 return;
2188 }
Ed Tanous271584a2019-07-09 16:24:22 -07002189 for (uint64_t i = 0; i <= index; i++)
Jason M. Billse1f26342018-07-18 12:12:00 -07002190 {
2191 sd_journal_next(journal.get());
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002192 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2193 {
2194 messages::internalError(asyncResp->res);
2195 return;
2196 }
2197 if (firstEntry)
2198 {
2199 firstEntry = false;
2200 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002201 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002202 // Confirm that the entry ID matches what was requested
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002203 if (idStr != entryID)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002204 {
2205 messages::resourceMissingAtURI(asyncResp->res, entryID);
2206 return;
2207 }
2208
2209 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2210 asyncResp->res.jsonValue) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07002211 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002212 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002213 return;
2214 }
2215 }
2216};
2217
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002218class BMCDumpService : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002219{
2220 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002221 BMCDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002222 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002223 {
2224 entityPrivileges = {
2225 {boost::beast::http::verb::get, {{"Login"}}},
2226 {boost::beast::http::verb::head, {{"Login"}}},
2227 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2228 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2229 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2230 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2231 }
2232
2233 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002234 void doGet(crow::Response& res, const crow::Request&,
2235 const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002236 {
2237 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2238
2239 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002240 "/redfish/v1/Managers/bmc/LogServices/Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002241 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002242 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002243 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2244 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2245 asyncResp->res.jsonValue["Id"] = "Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002246 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
raviteja-bc9bb6862020-02-03 11:53:32 -06002247 asyncResp->res.jsonValue["Entries"] = {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002248 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"}};
2249 asyncResp->res.jsonValue["Actions"] = {
2250 {"#LogService.ClearLog",
2251 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2252 "Actions/LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002253 {"#LogService.CollectDiagnosticData",
2254 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2255 "Actions/LogService.CollectDiagnosticData"}}}};
raviteja-bc9bb6862020-02-03 11:53:32 -06002256 }
2257};
2258
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002259class BMCDumpEntryCollection : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002260{
2261 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002262 BMCDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002263 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002264 {
2265 entityPrivileges = {
2266 {boost::beast::http::verb::get, {{"Login"}}},
2267 {boost::beast::http::verb::head, {{"Login"}}},
2268 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2269 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2270 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2271 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2272 }
2273
2274 private:
2275 /**
2276 * Functions triggers appropriate requests on DBus
2277 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002278 void doGet(crow::Response& res, const crow::Request&,
2279 const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002280 {
2281 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2282
2283 asyncResp->res.jsonValue["@odata.type"] =
2284 "#LogEntryCollection.LogEntryCollection";
2285 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002286 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2287 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002288 asyncResp->res.jsonValue["Description"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002289 "Collection of BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002290
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002291 getDumpEntryCollection(asyncResp, "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002292 }
2293};
2294
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002295class BMCDumpEntry : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002296{
2297 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002298 BMCDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002299 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/",
raviteja-bc9bb6862020-02-03 11:53:32 -06002300 std::string())
2301 {
2302 entityPrivileges = {
2303 {boost::beast::http::verb::get, {{"Login"}}},
2304 {boost::beast::http::verb::head, {{"Login"}}},
2305 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2306 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2307 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2308 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2309 }
2310
2311 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002312 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002313 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002314 {
2315 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2316 if (params.size() != 1)
2317 {
2318 messages::internalError(asyncResp->res);
2319 return;
2320 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002321 getDumpEntryById(asyncResp, params[0], "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002322 }
2323
Ed Tanouscb13a392020-07-25 19:02:03 +00002324 void doDelete(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002325 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002326 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002327 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
raviteja-bc9bb6862020-02-03 11:53:32 -06002328 if (params.size() != 1)
2329 {
2330 messages::internalError(asyncResp->res);
2331 return;
2332 }
Stanley Chu98782562020-11-04 16:10:24 +08002333 deleteDumpEntry(asyncResp, params[0], "bmc");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002334 }
2335};
raviteja-bc9bb6862020-02-03 11:53:32 -06002336
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002337class BMCDumpCreate : public Node
2338{
2339 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002340 BMCDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002341 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002342 "Actions/"
2343 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002344 {
2345 entityPrivileges = {
2346 {boost::beast::http::verb::get, {{"Login"}}},
2347 {boost::beast::http::verb::head, {{"Login"}}},
2348 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2349 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2350 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2351 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2352 }
2353
2354 private:
2355 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002356 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002357 {
2358 createDump(res, req, "BMC");
2359 }
2360};
2361
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002362class BMCDumpClear : public Node
2363{
2364 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002365 BMCDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002366 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
2367 "Actions/"
2368 "LogService.ClearLog/")
2369 {
2370 entityPrivileges = {
2371 {boost::beast::http::verb::get, {{"Login"}}},
2372 {boost::beast::http::verb::head, {{"Login"}}},
2373 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2374 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2375 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2376 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2377 }
2378
2379 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002380 void doPost(crow::Response& res, const crow::Request&,
2381 const std::vector<std::string>&) override
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002382 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -05002383 clearDump(res, "BMC");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002384 }
2385};
2386
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002387class SystemDumpService : public Node
2388{
2389 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002390 SystemDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002391 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/")
2392 {
2393 entityPrivileges = {
2394 {boost::beast::http::verb::get, {{"Login"}}},
2395 {boost::beast::http::verb::head, {{"Login"}}},
2396 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2397 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2398 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2399 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2400 }
raviteja-bc9bb6862020-02-03 11:53:32 -06002401
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002402 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002403 void doGet(crow::Response& res, const crow::Request&,
2404 const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002405 {
2406 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
raviteja-bc9bb6862020-02-03 11:53:32 -06002407
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002408 asyncResp->res.jsonValue["@odata.id"] =
2409 "/redfish/v1/Systems/system/LogServices/Dump";
2410 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002411 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002412 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2413 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2414 asyncResp->res.jsonValue["Id"] = "Dump";
2415 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2416 asyncResp->res.jsonValue["Entries"] = {
2417 {"@odata.id",
2418 "/redfish/v1/Systems/system/LogServices/Dump/Entries"}};
2419 asyncResp->res.jsonValue["Actions"] = {
2420 {"#LogService.ClearLog",
2421 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2422 "LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002423 {"#LogService.CollectDiagnosticData",
2424 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2425 "LogService.CollectDiagnosticData"}}}};
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002426 }
2427};
2428
2429class SystemDumpEntryCollection : public Node
2430{
2431 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002432 SystemDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002433 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
2434 {
2435 entityPrivileges = {
2436 {boost::beast::http::verb::get, {{"Login"}}},
2437 {boost::beast::http::verb::head, {{"Login"}}},
2438 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2439 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2440 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2441 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2442 }
2443
2444 private:
2445 /**
2446 * Functions triggers appropriate requests on DBus
2447 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002448 void doGet(crow::Response& res, const crow::Request&,
2449 const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002450 {
2451 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2452
2453 asyncResp->res.jsonValue["@odata.type"] =
2454 "#LogEntryCollection.LogEntryCollection";
2455 asyncResp->res.jsonValue["@odata.id"] =
2456 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2457 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2458 asyncResp->res.jsonValue["Description"] =
2459 "Collection of System Dump Entries";
2460
2461 getDumpEntryCollection(asyncResp, "System");
2462 }
2463};
2464
2465class SystemDumpEntry : public Node
2466{
2467 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002468 SystemDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002469 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/",
2470 std::string())
2471 {
2472 entityPrivileges = {
2473 {boost::beast::http::verb::get, {{"Login"}}},
2474 {boost::beast::http::verb::head, {{"Login"}}},
2475 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2476 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2477 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2478 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2479 }
2480
2481 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002482 void doGet(crow::Response& res, const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002483 const std::vector<std::string>& params) override
2484 {
2485 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2486 if (params.size() != 1)
2487 {
2488 messages::internalError(asyncResp->res);
2489 return;
2490 }
2491 getDumpEntryById(asyncResp, params[0], "System");
2492 }
2493
Ed Tanouscb13a392020-07-25 19:02:03 +00002494 void doDelete(crow::Response& res, const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002495 const std::vector<std::string>& params) override
2496 {
2497 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2498 if (params.size() != 1)
2499 {
2500 messages::internalError(asyncResp->res);
2501 return;
2502 }
Stanley Chu98782562020-11-04 16:10:24 +08002503 deleteDumpEntry(asyncResp, params[0], "system");
raviteja-bc9bb6862020-02-03 11:53:32 -06002504 }
2505};
2506
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002507class SystemDumpCreate : public Node
2508{
2509 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002510 SystemDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002511 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002512 "Actions/"
2513 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002514 {
2515 entityPrivileges = {
2516 {boost::beast::http::verb::get, {{"Login"}}},
2517 {boost::beast::http::verb::head, {{"Login"}}},
2518 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2519 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2520 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2521 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2522 }
2523
2524 private:
2525 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002526 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002527 {
2528 createDump(res, req, "System");
2529 }
2530};
2531
raviteja-b013487e2020-03-03 03:20:48 -06002532class SystemDumpClear : public Node
2533{
2534 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002535 SystemDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002536 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
raviteja-b013487e2020-03-03 03:20:48 -06002537 "Actions/"
2538 "LogService.ClearLog/")
2539 {
2540 entityPrivileges = {
2541 {boost::beast::http::verb::get, {{"Login"}}},
2542 {boost::beast::http::verb::head, {{"Login"}}},
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002543 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2544 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2545 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
raviteja-b013487e2020-03-03 03:20:48 -06002546 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2547 }
2548
2549 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002550 void doPost(crow::Response& res, const crow::Request&,
2551 const std::vector<std::string>&) override
raviteja-b013487e2020-03-03 03:20:48 -06002552 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -05002553 clearDump(res, "System");
raviteja-b013487e2020-03-03 03:20:48 -06002554 }
2555};
2556
Jason M. Bills424c4172019-03-21 13:50:33 -07002557class CrashdumpService : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002558{
2559 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002560 CrashdumpService(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002561 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002562 {
AppaRao Puli39460282020-04-07 17:03:04 +05302563 // Note: Deviated from redfish privilege registry for GET & HEAD
2564 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002565 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302566 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2567 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002568 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2569 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2570 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2571 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002572 }
2573
2574 private:
2575 /**
2576 * Functions triggers appropriate requests on DBus
2577 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002578 void doGet(crow::Response& res, const crow::Request&,
2579 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002580 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002581 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002582 // Copy over the static data to include the entries added by SubRoute
Ed Tanous0f74e642018-11-12 15:17:05 -08002583 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002584 "/redfish/v1/Systems/system/LogServices/Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002585 asyncResp->res.jsonValue["@odata.type"] =
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002586 "#LogService.v1_2_0.LogService";
Gunnar Mills4f50ae42020-02-06 15:29:57 -06002587 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2588 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2589 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002590 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2591 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Jason M. Billscd50aa42019-02-12 17:09:02 -08002592 asyncResp->res.jsonValue["Entries"] = {
2593 {"@odata.id",
Jason M. Bills424c4172019-03-21 13:50:33 -07002594 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07002595 asyncResp->res.jsonValue["Actions"] = {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002596 {"#LogService.ClearLog",
2597 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2598 "Actions/LogService.ClearLog"}}},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002599 {"#LogService.CollectDiagnosticData",
2600 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2601 "Actions/LogService.CollectDiagnosticData"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002602 }
2603};
2604
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002605class CrashdumpClear : public Node
2606{
2607 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002608 CrashdumpClear(App& app) :
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002609 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2610 "LogService.ClearLog/")
2611 {
AppaRao Puli39460282020-04-07 17:03:04 +05302612 // Note: Deviated from redfish privilege registry for GET & HEAD
2613 // method for security reasons.
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002614 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302615 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2616 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002617 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2618 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2619 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2620 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2621 }
2622
2623 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002624 void doPost(crow::Response& res, const crow::Request&,
2625 const std::vector<std::string>&) override
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002626 {
2627 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2628
2629 crow::connections::systemBus->async_method_call(
2630 [asyncResp](const boost::system::error_code ec,
Ed Tanouscb13a392020-07-25 19:02:03 +00002631 const std::string&) {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002632 if (ec)
2633 {
2634 messages::internalError(asyncResp->res);
2635 return;
2636 }
2637 messages::success(asyncResp->res);
2638 },
2639 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2640 }
2641};
2642
Ed Tanousb5a76932020-09-29 16:16:58 -07002643static void logCrashdumpEntry(const std::shared_ptr<AsyncResp>& asyncResp,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002644 const std::string& logID,
2645 nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002646{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002647 auto getStoredLogCallback =
2648 [asyncResp, logID, &logEntryJson](
2649 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002650 const std::vector<std::pair<std::string, VariantType>>& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002651 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002652 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002653 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2654 if (ec.value() ==
2655 boost::system::linux_error::bad_request_descriptor)
2656 {
2657 messages::resourceNotFound(asyncResp->res, "LogEntry",
2658 logID);
2659 }
2660 else
2661 {
2662 messages::internalError(asyncResp->res);
2663 }
2664 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002665 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002666
Johnathan Mantey043a0532020-03-10 17:15:28 -07002667 std::string timestamp{};
2668 std::string filename{};
2669 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002670 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002671
2672 if (filename.empty() || timestamp.empty())
2673 {
2674 messages::resourceMissingAtURI(asyncResp->res, logID);
2675 return;
2676 }
2677
2678 std::string crashdumpURI =
2679 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2680 logID + "/" + filename;
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002681 logEntryJson = {{"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002682 {"@odata.id", "/redfish/v1/Systems/system/"
2683 "LogServices/Crashdump/Entries/" +
2684 logID},
2685 {"Name", "CPU Crashdump"},
2686 {"Id", logID},
2687 {"EntryType", "Oem"},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002688 {"AdditionalDataURI", std::move(crashdumpURI)},
2689 {"DiagnosticDataType", "OEM"},
2690 {"OEMDiagnosticDataType", "PECICrashdump"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002691 {"Created", std::move(timestamp)}};
2692 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002693 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002694 std::move(getStoredLogCallback), crashdumpObject,
2695 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002696 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002697}
2698
Jason M. Bills424c4172019-03-21 13:50:33 -07002699class CrashdumpEntryCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002700{
2701 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002702 CrashdumpEntryCollection(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002703 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002704 {
AppaRao Puli39460282020-04-07 17:03:04 +05302705 // Note: Deviated from redfish privilege registry for GET & HEAD
2706 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002707 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302708 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2709 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002710 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2711 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2712 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2713 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002714 }
2715
2716 private:
2717 /**
2718 * Functions triggers appropriate requests on DBus
2719 */
Ed Tanouscb13a392020-07-25 19:02:03 +00002720 void doGet(crow::Response& res, const crow::Request&,
2721 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002722 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002723 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002724 // Collections don't include the static data added by SubRoute because
2725 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07002726 auto getLogEntriesCallback = [asyncResp](
2727 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002728 const std::vector<std::string>& resp) {
Jason M. Billse1f26342018-07-18 12:12:00 -07002729 if (ec)
2730 {
2731 if (ec.value() !=
2732 boost::system::errc::no_such_file_or_directory)
Ed Tanous1da66f72018-07-27 16:13:37 -07002733 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002734 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2735 << ec.message();
Jason M. Billsf12894f2018-10-09 12:45:45 -07002736 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002737 return;
Ed Tanous1da66f72018-07-27 16:13:37 -07002738 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002739 }
2740 asyncResp->res.jsonValue["@odata.type"] =
2741 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002742 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002743 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Jason M. Bills424c4172019-03-21 13:50:33 -07002744 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002745 asyncResp->res.jsonValue["Description"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002746 "Collection of Crashdump Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002747 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07002748 logEntryArray = nlohmann::json::array();
Jason M. Billse855dd22019-10-08 11:37:48 -07002749 std::vector<std::string> logIDs;
2750 // Get the list of log entries and build up an empty array big
2751 // enough to hold them
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002752 for (const std::string& objpath : resp)
Jason M. Billse1f26342018-07-18 12:12:00 -07002753 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002754 // Get the log ID
Ed Tanousf23b7292020-10-15 09:41:17 -07002755 std::size_t lastPos = objpath.rfind('/');
Jason M. Billse855dd22019-10-08 11:37:48 -07002756 if (lastPos == std::string::npos)
Jason M. Billse1f26342018-07-18 12:12:00 -07002757 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002758 continue;
Jason M. Billse1f26342018-07-18 12:12:00 -07002759 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002760 logIDs.emplace_back(objpath.substr(lastPos + 1));
2761
2762 // Add a space for the log entry to the array
2763 logEntryArray.push_back({});
2764 }
2765 // Now go through and set up async calls to fill in the entries
2766 size_t index = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002767 for (const std::string& logID : logIDs)
Jason M. Billse855dd22019-10-08 11:37:48 -07002768 {
2769 // Add the log entry to the array
2770 logCrashdumpEntry(asyncResp, logID, logEntryArray[index++]);
Jason M. Billse1f26342018-07-18 12:12:00 -07002771 }
2772 asyncResp->res.jsonValue["Members@odata.count"] =
2773 logEntryArray.size();
2774 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002775 crow::connections::systemBus->async_method_call(
2776 std::move(getLogEntriesCallback),
2777 "xyz.openbmc_project.ObjectMapper",
2778 "/xyz/openbmc_project/object_mapper",
2779 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002780 std::array<const char*, 1>{crashdumpInterface});
Ed Tanous1da66f72018-07-27 16:13:37 -07002781 }
2782};
2783
Jason M. Bills424c4172019-03-21 13:50:33 -07002784class CrashdumpEntry : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002785{
2786 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002787 CrashdumpEntry(App& app) :
Jason M. Billsd53dd412019-02-12 17:16:22 -08002788 Node(app,
Jason M. Bills424c4172019-03-21 13:50:33 -07002789 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/",
Ed Tanous1da66f72018-07-27 16:13:37 -07002790 std::string())
2791 {
AppaRao Puli39460282020-04-07 17:03:04 +05302792 // Note: Deviated from redfish privilege registry for GET & HEAD
2793 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002794 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302795 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2796 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002797 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2798 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2799 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2800 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002801 }
2802
2803 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002804 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002805 const std::vector<std::string>& params) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002806 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002807 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002808 if (params.size() != 1)
2809 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002810 messages::internalError(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002811 return;
2812 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002813 const std::string& logID = params[0];
Jason M. Billse855dd22019-10-08 11:37:48 -07002814 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2815 }
2816};
2817
2818class CrashdumpFile : public Node
2819{
2820 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002821 CrashdumpFile(App& app) :
Jason M. Billse855dd22019-10-08 11:37:48 -07002822 Node(app,
2823 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/"
2824 "<str>/",
2825 std::string(), std::string())
2826 {
AppaRao Puli39460282020-04-07 17:03:04 +05302827 // Note: Deviated from redfish privilege registry for GET & HEAD
2828 // method for security reasons.
Jason M. Billse855dd22019-10-08 11:37:48 -07002829 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302830 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2831 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse855dd22019-10-08 11:37:48 -07002832 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2833 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2834 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2835 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2836 }
2837
2838 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00002839 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002840 const std::vector<std::string>& params) override
Jason M. Billse855dd22019-10-08 11:37:48 -07002841 {
2842 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
2843 if (params.size() != 2)
2844 {
2845 messages::internalError(asyncResp->res);
2846 return;
2847 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002848 const std::string& logID = params[0];
2849 const std::string& fileName = params[1];
Jason M. Billse855dd22019-10-08 11:37:48 -07002850
Johnathan Mantey043a0532020-03-10 17:15:28 -07002851 auto getStoredLogCallback =
2852 [asyncResp, logID, fileName](
2853 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002854 const std::vector<std::pair<std::string, VariantType>>& resp) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002855 if (ec)
2856 {
2857 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2858 << ec.message();
2859 messages::internalError(asyncResp->res);
2860 return;
2861 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002862
Johnathan Mantey043a0532020-03-10 17:15:28 -07002863 std::string dbusFilename{};
2864 std::string dbusTimestamp{};
2865 std::string dbusFilepath{};
Jason M. Billse855dd22019-10-08 11:37:48 -07002866
Ed Tanous2c70f802020-09-28 14:29:23 -07002867 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002868 dbusFilepath);
2869
2870 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2871 dbusFilepath.empty())
2872 {
2873 messages::resourceMissingAtURI(asyncResp->res, fileName);
2874 return;
2875 }
2876
2877 // Verify the file name parameter is correct
2878 if (fileName != dbusFilename)
2879 {
2880 messages::resourceMissingAtURI(asyncResp->res, fileName);
2881 return;
2882 }
2883
2884 if (!std::filesystem::exists(dbusFilepath))
2885 {
2886 messages::resourceMissingAtURI(asyncResp->res, fileName);
2887 return;
2888 }
2889 std::ifstream ifs(dbusFilepath, std::ios::in |
2890 std::ios::binary |
2891 std::ios::ate);
2892 std::ifstream::pos_type fileSize = ifs.tellg();
2893 if (fileSize < 0)
2894 {
2895 messages::generalError(asyncResp->res);
2896 return;
2897 }
2898 ifs.seekg(0, std::ios::beg);
2899
2900 auto crashData = std::make_unique<char[]>(
2901 static_cast<unsigned int>(fileSize));
2902
2903 ifs.read(crashData.get(), static_cast<int>(fileSize));
2904
2905 // The cast to std::string is intentional in order to use the
2906 // assign() that applies move mechanics
2907 asyncResp->res.body().assign(
2908 static_cast<std::string>(crashData.get()));
2909
2910 // Configure this to be a file download when accessed from
2911 // a browser
2912 asyncResp->res.addHeader("Content-Disposition", "attachment");
2913 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002914 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002915 std::move(getStoredLogCallback), crashdumpObject,
2916 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002917 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Ed Tanous1da66f72018-07-27 16:13:37 -07002918 }
2919};
2920
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002921class CrashdumpCollect : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002922{
2923 public:
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002924 CrashdumpCollect(App& app) :
2925 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2926 "LogService.CollectDiagnosticData/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002927 {
AppaRao Puli39460282020-04-07 17:03:04 +05302928 // Note: Deviated from redfish privilege registry for GET & HEAD
2929 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002930 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302931 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2932 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
2933 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2934 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2935 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2936 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002937 }
2938
2939 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002940 void doPost(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002941 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002942 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002943 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002944
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002945 std::string diagnosticDataType;
2946 std::string oemDiagnosticDataType;
2947 if (!redfish::json_util::readJson(
2948 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2949 "OEMDiagnosticDataType", oemDiagnosticDataType))
2950 {
2951 return;
2952 }
2953
2954 if (diagnosticDataType != "OEM")
2955 {
2956 BMCWEB_LOG_ERROR
2957 << "Only OEM DiagnosticDataType supported for Crashdump";
2958 messages::actionParameterValueFormatError(
2959 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2960 "CollectDiagnosticData");
2961 return;
2962 }
2963
2964 auto collectCrashdumpCallback = [asyncResp, req](
2965 const boost::system::error_code ec,
2966 const std::string&) {
James Feist46229572020-02-19 15:11:58 -08002967 if (ec)
2968 {
2969 if (ec.value() == boost::system::errc::operation_not_supported)
Ed Tanous1da66f72018-07-27 16:13:37 -07002970 {
James Feist46229572020-02-19 15:11:58 -08002971 messages::resourceInStandby(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002972 }
James Feist46229572020-02-19 15:11:58 -08002973 else if (ec.value() ==
2974 boost::system::errc::device_or_resource_busy)
2975 {
2976 messages::serviceTemporarilyUnavailable(asyncResp->res,
2977 "60");
2978 }
2979 else
2980 {
2981 messages::internalError(asyncResp->res);
2982 }
2983 return;
2984 }
2985 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002986 [](boost::system::error_code err, sdbusplus::message::message&,
2987 const std::shared_ptr<task::TaskData>& taskData) {
James Feist66afe4f2020-02-24 13:09:58 -08002988 if (!err)
2989 {
James Feiste5d50062020-05-11 17:29:00 -07002990 taskData->messages.emplace_back(
2991 messages::taskCompletedOK(
2992 std::to_string(taskData->index)));
James Feist831d6b02020-03-12 16:31:30 -07002993 taskData->state = "Completed";
James Feist66afe4f2020-02-24 13:09:58 -08002994 }
James Feist32898ce2020-03-10 16:16:52 -07002995 return task::completed;
James Feist66afe4f2020-02-24 13:09:58 -08002996 },
James Feist46229572020-02-19 15:11:58 -08002997 "type='signal',interface='org.freedesktop.DBus.Properties',"
2998 "member='PropertiesChanged',arg0namespace='com.intel."
2999 "crashdump'");
3000 task->startTimer(std::chrono::minutes(5));
3001 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -07003002 task->payload.emplace(req);
James Feist46229572020-02-19 15:11:58 -08003003 };
Ed Tanous1da66f72018-07-27 16:13:37 -07003004
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003005 if (oemDiagnosticDataType == "OnDemand")
3006 {
3007 crow::connections::systemBus->async_method_call(
3008 std::move(collectCrashdumpCallback), crashdumpObject,
3009 crashdumpPath, crashdumpOnDemandInterface,
3010 "GenerateOnDemandLog");
3011 }
3012 else if (oemDiagnosticDataType == "Telemetry")
3013 {
3014 crow::connections::systemBus->async_method_call(
3015 std::move(collectCrashdumpCallback), crashdumpObject,
3016 crashdumpPath, crashdumpTelemetryInterface,
3017 "GenerateTelemetryLog");
3018 }
3019 else
3020 {
3021 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3022 << oemDiagnosticDataType;
3023 messages::actionParameterValueFormatError(
3024 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3025 "CollectDiagnosticData");
3026 return;
3027 }
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003028 }
3029};
3030
Andrew Geisslercb92c032018-08-17 07:56:14 -07003031/**
3032 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3033 */
3034class DBusLogServiceActionsClear : public Node
3035{
3036 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003037 DBusLogServiceActionsClear(App& app) :
Andrew Geisslercb92c032018-08-17 07:56:14 -07003038 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
Gunnar Mills7af91512020-04-14 22:16:57 -05003039 "LogService.ClearLog/")
Andrew Geisslercb92c032018-08-17 07:56:14 -07003040 {
3041 entityPrivileges = {
3042 {boost::beast::http::verb::get, {{"Login"}}},
3043 {boost::beast::http::verb::head, {{"Login"}}},
3044 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3045 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3046 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3047 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3048 }
3049
3050 private:
3051 /**
3052 * Function handles POST method request.
3053 * The Clear Log actions does not require any parameter.The action deletes
3054 * all entries found in the Entries collection for this Log Service.
3055 */
Ed Tanouscb13a392020-07-25 19:02:03 +00003056 void doPost(crow::Response& res, const crow::Request&,
3057 const std::vector<std::string>&) override
Andrew Geisslercb92c032018-08-17 07:56:14 -07003058 {
3059 BMCWEB_LOG_DEBUG << "Do delete all entries.";
3060
3061 auto asyncResp = std::make_shared<AsyncResp>(res);
3062 // Process response from Logging service.
Ed Tanous2c70f802020-09-28 14:29:23 -07003063 auto respHandler = [asyncResp](const boost::system::error_code ec) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07003064 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3065 if (ec)
3066 {
3067 // TODO Handle for specific error code
3068 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3069 asyncResp->res.result(
3070 boost::beast::http::status::internal_server_error);
3071 return;
3072 }
3073
3074 asyncResp->res.result(boost::beast::http::status::no_content);
3075 };
3076
3077 // Make call to Logging service to request Clear Log
3078 crow::connections::systemBus->async_method_call(
Ed Tanous2c70f802020-09-28 14:29:23 -07003079 respHandler, "xyz.openbmc_project.Logging",
Andrew Geisslercb92c032018-08-17 07:56:14 -07003080 "/xyz/openbmc_project/logging",
3081 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3082 }
3083};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003084
3085/****************************************************
3086 * Redfish PostCode interfaces
3087 * using DBUS interface: getPostCodesTS
3088 ******************************************************/
3089class PostCodesLogService : public Node
3090{
3091 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003092 PostCodesLogService(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003093 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
3094 {
3095 entityPrivileges = {
3096 {boost::beast::http::verb::get, {{"Login"}}},
3097 {boost::beast::http::verb::head, {{"Login"}}},
3098 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3099 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3100 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3101 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3102 }
3103
3104 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003105 void doGet(crow::Response& res, const crow::Request&,
3106 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003107 {
3108 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3109
3110 asyncResp->res.jsonValue = {
3111 {"@odata.id", "/redfish/v1/Systems/system/LogServices/PostCodes"},
3112 {"@odata.type", "#LogService.v1_1_0.LogService"},
ZhikuiRena3316fc2020-01-29 14:58:08 -08003113 {"Name", "POST Code Log Service"},
3114 {"Description", "POST Code Log Service"},
3115 {"Id", "BIOS POST Code Log"},
3116 {"OverWritePolicy", "WrapsWhenFull"},
3117 {"Entries",
3118 {{"@odata.id",
3119 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"}}}};
3120 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3121 {"target", "/redfish/v1/Systems/system/LogServices/PostCodes/"
3122 "Actions/LogService.ClearLog"}};
3123 }
3124};
3125
3126class PostCodesClear : public Node
3127{
3128 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003129 PostCodesClear(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003130 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/"
3131 "LogService.ClearLog/")
3132 {
3133 entityPrivileges = {
3134 {boost::beast::http::verb::get, {{"Login"}}},
3135 {boost::beast::http::verb::head, {{"Login"}}},
AppaRao Puli39460282020-04-07 17:03:04 +05303136 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
3137 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
3138 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
3139 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003140 }
3141
3142 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003143 void doPost(crow::Response& res, const crow::Request&,
3144 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003145 {
3146 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
3147
3148 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3149 // Make call to post-code service to request clear all
3150 crow::connections::systemBus->async_method_call(
3151 [asyncResp](const boost::system::error_code ec) {
3152 if (ec)
3153 {
3154 // TODO Handle for specific error code
3155 BMCWEB_LOG_ERROR
3156 << "doClearPostCodes resp_handler got error " << ec;
3157 asyncResp->res.result(
3158 boost::beast::http::status::internal_server_error);
3159 messages::internalError(asyncResp->res);
3160 return;
3161 }
3162 },
Jonathan Doman15124762021-01-07 17:54:17 -08003163 "xyz.openbmc_project.State.Boot.PostCode0",
3164 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003165 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3166 }
3167};
3168
3169static void fillPostCodeEntry(
Ed Tanousb5a76932020-09-29 16:16:58 -07003170 const std::shared_ptr<AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303171 const boost::container::flat_map<
3172 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003173 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3174 const uint64_t skip = 0, const uint64_t top = 0)
3175{
3176 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003177 const message_registries::Message* message =
ZhikuiRena3316fc2020-01-29 14:58:08 -08003178 message_registries::getMessage("OpenBMC.0.1.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003179
3180 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003181 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003182
3183 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303184 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3185 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003186 {
3187 currentCodeIndex++;
3188 std::string postcodeEntryID =
3189 "B" + std::to_string(bootIndex) + "-" +
3190 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3191
3192 uint64_t usecSinceEpoch = code.first;
3193 uint64_t usTimeOffset = 0;
3194
3195 if (1 == currentCodeIndex)
3196 { // already incremented
3197 firstCodeTimeUs = code.first;
3198 }
3199 else
3200 {
3201 usTimeOffset = code.first - firstCodeTimeUs;
3202 }
3203
3204 // skip if no specific codeIndex is specified and currentCodeIndex does
3205 // not fall between top and skip
3206 if ((codeIndex == 0) &&
3207 (currentCodeIndex <= skip || currentCodeIndex > top))
3208 {
3209 continue;
3210 }
3211
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003212 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003213 // currentIndex
3214 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3215 {
3216 // This is done for simplicity. 1st entry is needed to calculate
3217 // time offset. To improve efficiency, one can get to the entry
3218 // directly (possibly with flatmap's nth method)
3219 continue;
3220 }
3221
3222 // currentCodeIndex is within top and skip or equal to specified code
3223 // index
3224
3225 // Get the Created time from the timestamp
3226 std::string entryTimeStr;
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -05003227 entryTimeStr = crow::utility::getDateTime(
3228 static_cast<std::time_t>(usecSinceEpoch / 1000 / 1000));
ZhikuiRena3316fc2020-01-29 14:58:08 -08003229
3230 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3231 std::ostringstream hexCode;
3232 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303233 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003234 std::ostringstream timeOffsetStr;
3235 // Set Fixed -Point Notation
3236 timeOffsetStr << std::fixed;
3237 // Set precision to 4 digits
3238 timeOffsetStr << std::setprecision(4);
3239 // Add double to stream
3240 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3241 std::vector<std::string> messageArgs = {
3242 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3243
3244 // Get MessageArgs template from message registry
3245 std::string msg;
3246 if (message != nullptr)
3247 {
3248 msg = message->message;
3249
3250 // fill in this post code value
3251 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003252 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003253 {
3254 std::string argStr = "%" + std::to_string(++i);
3255 size_t argPos = msg.find(argStr);
3256 if (argPos != std::string::npos)
3257 {
3258 msg.replace(argPos, argStr.length(), messageArg);
3259 }
3260 }
3261 }
3262
Tim Leed4342a92020-04-27 11:47:58 +08003263 // Get Severity template from message registry
3264 std::string severity;
3265 if (message != nullptr)
3266 {
3267 severity = message->severity;
3268 }
3269
ZhikuiRena3316fc2020-01-29 14:58:08 -08003270 // add to AsyncResp
3271 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003272 nlohmann::json& bmcLogEntry = logEntryArray.back();
Gunnar Mills743e9a12020-10-26 12:44:53 -05003273 bmcLogEntry = {{"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
3274 {"@odata.id", "/redfish/v1/Systems/system/LogServices/"
3275 "PostCodes/Entries/" +
3276 postcodeEntryID},
3277 {"Name", "POST Code Log Entry"},
3278 {"Id", postcodeEntryID},
3279 {"Message", std::move(msg)},
3280 {"MessageId", "OpenBMC.0.1.BIOSPOSTCode"},
3281 {"MessageArgs", std::move(messageArgs)},
3282 {"EntryType", "Event"},
3283 {"Severity", std::move(severity)},
3284 {"Created", entryTimeStr}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003285 }
3286}
3287
Ed Tanousb5a76932020-09-29 16:16:58 -07003288static void getPostCodeForEntry(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003289 const uint16_t bootIndex,
3290 const uint64_t codeIndex)
3291{
3292 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303293 [aResp, bootIndex,
3294 codeIndex](const boost::system::error_code ec,
3295 const boost::container::flat_map<
3296 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3297 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003298 if (ec)
3299 {
3300 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3301 messages::internalError(aResp->res);
3302 return;
3303 }
3304
3305 // skip the empty postcode boots
3306 if (postcode.empty())
3307 {
3308 return;
3309 }
3310
3311 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3312
3313 aResp->res.jsonValue["Members@odata.count"] =
3314 aResp->res.jsonValue["Members"].size();
3315 },
Jonathan Doman15124762021-01-07 17:54:17 -08003316 "xyz.openbmc_project.State.Boot.PostCode0",
3317 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003318 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3319 bootIndex);
3320}
3321
Ed Tanousb5a76932020-09-29 16:16:58 -07003322static void getPostCodeForBoot(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003323 const uint16_t bootIndex,
3324 const uint16_t bootCount,
3325 const uint64_t entryCount, const uint64_t skip,
3326 const uint64_t top)
3327{
3328 crow::connections::systemBus->async_method_call(
3329 [aResp, bootIndex, bootCount, entryCount, skip,
3330 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303331 const boost::container::flat_map<
3332 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3333 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003334 if (ec)
3335 {
3336 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3337 messages::internalError(aResp->res);
3338 return;
3339 }
3340
3341 uint64_t endCount = entryCount;
3342 if (!postcode.empty())
3343 {
3344 endCount = entryCount + postcode.size();
3345
3346 if ((skip < endCount) && ((top + skip) > entryCount))
3347 {
3348 uint64_t thisBootSkip =
3349 std::max(skip, entryCount) - entryCount;
3350 uint64_t thisBootTop =
3351 std::min(top + skip, endCount) - entryCount;
3352
3353 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3354 thisBootSkip, thisBootTop);
3355 }
3356 aResp->res.jsonValue["Members@odata.count"] = endCount;
3357 }
3358
3359 // continue to previous bootIndex
3360 if (bootIndex < bootCount)
3361 {
3362 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3363 bootCount, endCount, skip, top);
3364 }
3365 else
3366 {
3367 aResp->res.jsonValue["Members@odata.nextLink"] =
3368 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3369 "Entries?$skip=" +
3370 std::to_string(skip + top);
3371 }
3372 },
Jonathan Doman15124762021-01-07 17:54:17 -08003373 "xyz.openbmc_project.State.Boot.PostCode0",
3374 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003375 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3376 bootIndex);
3377}
3378
Ed Tanousb5a76932020-09-29 16:16:58 -07003379static void getCurrentBootNumber(const std::shared_ptr<AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003380 const uint64_t skip, const uint64_t top)
3381{
3382 uint64_t entryCount = 0;
3383 crow::connections::systemBus->async_method_call(
3384 [aResp, entryCount, skip,
3385 top](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003386 const std::variant<uint16_t>& bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003387 if (ec)
3388 {
3389 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3390 messages::internalError(aResp->res);
3391 return;
3392 }
3393 auto pVal = std::get_if<uint16_t>(&bootCount);
3394 if (pVal)
3395 {
3396 getPostCodeForBoot(aResp, 1, *pVal, entryCount, skip, top);
3397 }
3398 else
3399 {
3400 BMCWEB_LOG_DEBUG << "Post code boot index failed.";
3401 }
3402 },
Jonathan Doman15124762021-01-07 17:54:17 -08003403 "xyz.openbmc_project.State.Boot.PostCode0",
3404 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003405 "org.freedesktop.DBus.Properties", "Get",
3406 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount");
3407}
3408
3409class PostCodesEntryCollection : public Node
3410{
3411 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003412 PostCodesEntryCollection(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003413 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
3414 {
3415 entityPrivileges = {
3416 {boost::beast::http::verb::get, {{"Login"}}},
3417 {boost::beast::http::verb::head, {{"Login"}}},
3418 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3419 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3420 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3421 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3422 }
3423
3424 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003425 void doGet(crow::Response& res, const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00003426 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003427 {
3428 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3429
3430 asyncResp->res.jsonValue["@odata.type"] =
3431 "#LogEntryCollection.LogEntryCollection";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003432 asyncResp->res.jsonValue["@odata.id"] =
3433 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3434 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3435 asyncResp->res.jsonValue["Description"] =
3436 "Collection of POST Code Log Entries";
3437 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3438 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3439
3440 uint64_t skip = 0;
3441 uint64_t top = maxEntriesPerPage; // Show max entries by default
3442 if (!getSkipParam(asyncResp->res, req, skip))
3443 {
3444 return;
3445 }
3446 if (!getTopParam(asyncResp->res, req, top))
3447 {
3448 return;
3449 }
3450 getCurrentBootNumber(asyncResp, skip, top);
3451 }
3452};
3453
3454class PostCodesEntry : public Node
3455{
3456 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003457 PostCodesEntry(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003458 Node(app,
3459 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/",
3460 std::string())
3461 {
3462 entityPrivileges = {
3463 {boost::beast::http::verb::get, {{"Login"}}},
3464 {boost::beast::http::verb::head, {{"Login"}}},
3465 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3466 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3467 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3468 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3469 }
3470
3471 private:
Ed Tanouscb13a392020-07-25 19:02:03 +00003472 void doGet(crow::Response& res, const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003473 const std::vector<std::string>& params) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003474 {
3475 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
3476 if (params.size() != 1)
3477 {
3478 messages::internalError(asyncResp->res);
3479 return;
3480 }
3481
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003482 const std::string& targetID = params[0];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003483
3484 size_t bootPos = targetID.find('B');
3485 if (bootPos == std::string::npos)
3486 {
3487 // Requested ID was not found
3488 messages::resourceMissingAtURI(asyncResp->res, targetID);
3489 return;
3490 }
3491 std::string_view bootIndexStr(targetID);
3492 bootIndexStr.remove_prefix(bootPos + 1);
3493 uint16_t bootIndex = 0;
3494 uint64_t codeIndex = 0;
3495 size_t dashPos = bootIndexStr.find('-');
3496
3497 if (dashPos == std::string::npos)
3498 {
3499 return;
3500 }
3501 std::string_view codeIndexStr(bootIndexStr);
3502 bootIndexStr.remove_suffix(dashPos);
3503 codeIndexStr.remove_prefix(dashPos + 1);
3504
3505 bootIndex = static_cast<uint16_t>(
Ed Tanous23a21a12020-07-25 04:45:05 +00003506 strtoul(std::string(bootIndexStr).c_str(), nullptr, 0));
3507 codeIndex = strtoul(std::string(codeIndexStr).c_str(), nullptr, 0);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003508 if (bootIndex == 0 || codeIndex == 0)
3509 {
3510 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3511 << params[0];
3512 }
3513
3514 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003515 asyncResp->res.jsonValue["@odata.id"] =
3516 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3517 "Entries";
3518 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3519 asyncResp->res.jsonValue["Description"] =
3520 "Collection of POST Code Log Entries";
3521 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3522 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3523
3524 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3525 }
3526};
3527
Ed Tanous1da66f72018-07-27 16:13:37 -07003528} // namespace redfish