blob: efed76463bf4a218322a854a5cd72e22804059a8 [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
zhanghch058d1b46d2021-04-01 11:18:24 +0800184static bool getSkipParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
185 const crow::Request& req, 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
zhanghch058d1b46d2021-04-01 11:18:24 +0800197 messages::queryParameterValueTypeError(
198 asyncResp->res, std::string(skipParam), "$skip");
Jason M. Bills16428a12018-11-02 12:42:29 -0700199 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;
zhanghch058d1b46d2021-04-01 11:18:24 +0800206static bool getTopParam(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
207 const crow::Request& req, 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 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800218 messages::queryParameterValueTypeError(
219 asyncResp->res, std::string(topParam), "$top");
Jason M. Bills16428a12018-11-02 12:42:29 -0700220 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(
zhanghch058d1b46d2021-04-01 11:18:24 +0800226 asyncResp->res, std::to_string(top), "$top",
Jason M. Bills16428a12018-11-02 12:42:29 -0700227 "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
zhanghch058d1b46d2021-04-01 11:18:24 +0800314static bool
315 getTimestampFromID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
316 const std::string& entryID, uint64_t& timestamp,
317 uint64_t& index)
Jason M. Bills16428a12018-11-02 12:42:29 -0700318{
319 if (entryID.empty())
320 {
321 return false;
322 }
323 // Convert the unique ID back to a timestamp to find the entry
Ed Tanous39e77502019-03-04 17:35:53 -0800324 std::string_view tsStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700325
Ed Tanous81ce6092020-12-17 16:54:55 +0000326 auto underscorePos = tsStr.find('_');
Jason M. Bills16428a12018-11-02 12:42:29 -0700327 if (underscorePos != tsStr.npos)
328 {
329 // Timestamp has an index
330 tsStr.remove_suffix(tsStr.size() - underscorePos);
Ed Tanous39e77502019-03-04 17:35:53 -0800331 std::string_view indexStr(entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700332 indexStr.remove_prefix(underscorePos + 1);
333 std::size_t pos;
334 try
335 {
Ed Tanous39e77502019-03-04 17:35:53 -0800336 index = std::stoul(std::string(indexStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700337 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500338 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700339 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800340 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700341 return false;
342 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500343 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700344 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800345 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700346 return false;
347 }
348 if (pos != indexStr.size())
349 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800350 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700351 return false;
352 }
353 }
354 // Timestamp has no index
355 std::size_t pos;
356 try
357 {
Ed Tanous39e77502019-03-04 17:35:53 -0800358 timestamp = std::stoull(std::string(tsStr), &pos);
Jason M. Bills16428a12018-11-02 12:42:29 -0700359 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500360 catch (std::invalid_argument&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700361 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800362 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700363 return false;
364 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500365 catch (std::out_of_range&)
Jason M. Bills16428a12018-11-02 12:42:29 -0700366 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800367 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700368 return false;
369 }
370 if (pos != tsStr.size())
371 {
zhanghch058d1b46d2021-04-01 11:18:24 +0800372 messages::resourceMissingAtURI(asyncResp->res, entryID);
Jason M. Bills16428a12018-11-02 12:42:29 -0700373 return false;
374 }
375 return true;
376}
377
Jason M. Bills95820182019-04-22 16:25:34 -0700378static bool
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500379 getRedfishLogFiles(std::vector<std::filesystem::path>& redfishLogFiles)
Jason M. Bills95820182019-04-22 16:25:34 -0700380{
381 static const std::filesystem::path redfishLogDir = "/var/log";
382 static const std::string redfishLogFilename = "redfish";
383
384 // Loop through the directory looking for redfish log files
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500385 for (const std::filesystem::directory_entry& dirEnt :
Jason M. Bills95820182019-04-22 16:25:34 -0700386 std::filesystem::directory_iterator(redfishLogDir))
387 {
388 // If we find a redfish log file, save the path
389 std::string filename = dirEnt.path().filename();
390 if (boost::starts_with(filename, redfishLogFilename))
391 {
392 redfishLogFiles.emplace_back(redfishLogDir / filename);
393 }
394 }
395 // As the log files rotate, they are appended with a ".#" that is higher for
396 // the older logs. Since we don't expect more than 10 log files, we
397 // can just sort the list to get them in order from newest to oldest
398 std::sort(redfishLogFiles.begin(), redfishLogFiles.end());
399
400 return !redfishLogFiles.empty();
401}
402
zhanghch058d1b46d2021-04-01 11:18:24 +0800403inline void
404 getDumpEntryCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
405 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500406{
407 std::string dumpPath;
408 if (dumpType == "BMC")
409 {
410 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
411 }
412 else if (dumpType == "System")
413 {
414 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
415 }
416 else
417 {
418 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
419 messages::internalError(asyncResp->res);
420 return;
421 }
422
423 crow::connections::systemBus->async_method_call(
424 [asyncResp, dumpPath, dumpType](const boost::system::error_code ec,
425 GetManagedObjectsType& resp) {
426 if (ec)
427 {
428 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
429 messages::internalError(asyncResp->res);
430 return;
431 }
432
433 nlohmann::json& entriesArray = asyncResp->res.jsonValue["Members"];
434 entriesArray = nlohmann::json::array();
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500435 std::string dumpEntryPath =
436 "/xyz/openbmc_project/dump/" +
437 std::string(boost::algorithm::to_lower_copy(dumpType)) +
438 "/entry/";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500439
440 for (auto& object : resp)
441 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500442 if (object.first.str.find(dumpEntryPath) == std::string::npos)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500443 {
444 continue;
445 }
446 std::time_t timestamp;
447 uint64_t size = 0;
448 entriesArray.push_back({});
449 nlohmann::json& thisEntry = entriesArray.back();
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000450
451 std::string entryID = object.first.filename();
452 if (entryID.empty())
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500453 {
454 continue;
455 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500456
457 for (auto& interfaceMap : object.second)
458 {
459 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
460 {
461
462 for (auto& propertyMap : interfaceMap.second)
463 {
464 if (propertyMap.first == "Size")
465 {
466 auto sizePtr =
467 std::get_if<uint64_t>(&propertyMap.second);
468 if (sizePtr == nullptr)
469 {
470 messages::internalError(asyncResp->res);
471 break;
472 }
473 size = *sizePtr;
474 break;
475 }
476 }
477 }
478 else if (interfaceMap.first ==
479 "xyz.openbmc_project.Time.EpochTime")
480 {
481
482 for (auto& propertyMap : interfaceMap.second)
483 {
484 if (propertyMap.first == "Elapsed")
485 {
486 const uint64_t* usecsTimeStamp =
487 std::get_if<uint64_t>(&propertyMap.second);
488 if (usecsTimeStamp == nullptr)
489 {
490 messages::internalError(asyncResp->res);
491 break;
492 }
493 timestamp =
494 static_cast<std::time_t>(*usecsTimeStamp);
495 break;
496 }
497 }
498 }
499 }
500
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500501 thisEntry["@odata.type"] = "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500502 thisEntry["@odata.id"] = dumpPath + entryID;
503 thisEntry["Id"] = entryID;
504 thisEntry["EntryType"] = "Event";
505 thisEntry["Created"] = crow::utility::getDateTime(timestamp);
506 thisEntry["Name"] = dumpType + " Dump Entry";
507
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500508 thisEntry["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500509
510 if (dumpType == "BMC")
511 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500512 thisEntry["DiagnosticDataType"] = "Manager";
513 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500514 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
515 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500516 }
517 else if (dumpType == "System")
518 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500519 thisEntry["DiagnosticDataType"] = "OEM";
520 thisEntry["OEMDiagnosticDataType"] = "System";
521 thisEntry["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500522 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
523 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500524 }
525 }
526 asyncResp->res.jsonValue["Members@odata.count"] =
527 entriesArray.size();
528 },
529 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
530 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
531}
532
zhanghch058d1b46d2021-04-01 11:18:24 +0800533inline void
534 getDumpEntryById(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
535 const std::string& entryID, const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500536{
537 std::string dumpPath;
538 if (dumpType == "BMC")
539 {
540 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
541 }
542 else if (dumpType == "System")
543 {
544 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
545 }
546 else
547 {
548 BMCWEB_LOG_ERROR << "Invalid dump type" << dumpType;
549 messages::internalError(asyncResp->res);
550 return;
551 }
552
553 crow::connections::systemBus->async_method_call(
554 [asyncResp, entryID, dumpPath, dumpType](
555 const boost::system::error_code ec, GetManagedObjectsType& resp) {
556 if (ec)
557 {
558 BMCWEB_LOG_ERROR << "DumpEntry resp_handler got error " << ec;
559 messages::internalError(asyncResp->res);
560 return;
561 }
562
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500563 bool foundDumpEntry = false;
564 std::string dumpEntryPath =
565 "/xyz/openbmc_project/dump/" +
566 std::string(boost::algorithm::to_lower_copy(dumpType)) +
567 "/entry/";
568
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500569 for (auto& objectPath : resp)
570 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500571 if (objectPath.first.str != dumpEntryPath + entryID)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500572 {
573 continue;
574 }
575
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500576 foundDumpEntry = true;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500577 std::time_t timestamp;
578 uint64_t size = 0;
579
580 for (auto& interfaceMap : objectPath.second)
581 {
582 if (interfaceMap.first == "xyz.openbmc_project.Dump.Entry")
583 {
584 for (auto& propertyMap : interfaceMap.second)
585 {
586 if (propertyMap.first == "Size")
587 {
588 auto sizePtr =
589 std::get_if<uint64_t>(&propertyMap.second);
590 if (sizePtr == nullptr)
591 {
592 messages::internalError(asyncResp->res);
593 break;
594 }
595 size = *sizePtr;
596 break;
597 }
598 }
599 }
600 else if (interfaceMap.first ==
601 "xyz.openbmc_project.Time.EpochTime")
602 {
603 for (auto& propertyMap : interfaceMap.second)
604 {
605 if (propertyMap.first == "Elapsed")
606 {
607 const uint64_t* usecsTimeStamp =
608 std::get_if<uint64_t>(&propertyMap.second);
609 if (usecsTimeStamp == nullptr)
610 {
611 messages::internalError(asyncResp->res);
612 break;
613 }
614 timestamp =
615 static_cast<std::time_t>(*usecsTimeStamp);
616 break;
617 }
618 }
619 }
620 }
621
622 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500623 "#LogEntry.v1_7_0.LogEntry";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500624 asyncResp->res.jsonValue["@odata.id"] = dumpPath + entryID;
625 asyncResp->res.jsonValue["Id"] = entryID;
626 asyncResp->res.jsonValue["EntryType"] = "Event";
627 asyncResp->res.jsonValue["Created"] =
628 crow::utility::getDateTime(timestamp);
629 asyncResp->res.jsonValue["Name"] = dumpType + " Dump Entry";
630
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500631 asyncResp->res.jsonValue["AdditionalDataSizeBytes"] = size;
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500632
633 if (dumpType == "BMC")
634 {
Asmitha Karunanithid337bb72020-09-21 10:34:02 -0500635 asyncResp->res.jsonValue["DiagnosticDataType"] = "Manager";
636 asyncResp->res.jsonValue["AdditionalDataURI"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500637 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/" +
638 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500639 }
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"] =
Abhishek Patelde8d94a2021-05-13 22:57:36 -0500646 "/redfish/v1/Systems/system/LogServices/Dump/Entries/" +
647 entryID + "/attachment";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500648 }
649 }
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500650 if (foundDumpEntry == false)
651 {
652 BMCWEB_LOG_ERROR << "Can't find Dump Entry";
653 messages::internalError(asyncResp->res);
654 return;
655 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500656 },
657 "xyz.openbmc_project.Dump.Manager", "/xyz/openbmc_project/dump",
658 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
659}
660
zhanghch058d1b46d2021-04-01 11:18:24 +0800661inline void deleteDumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Stanley Chu98782562020-11-04 16:10:24 +0800662 const std::string& entryID,
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500663 const std::string& dumpType)
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500664{
George Liu3de8d8b2021-03-22 17:49:39 +0800665 auto respHandler = [asyncResp,
666 entryID](const boost::system::error_code ec) {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500667 BMCWEB_LOG_DEBUG << "Dump Entry doDelete callback: Done";
668 if (ec)
669 {
George Liu3de8d8b2021-03-22 17:49:39 +0800670 if (ec.value() == EBADR)
671 {
672 messages::resourceNotFound(asyncResp->res, "LogEntry", entryID);
673 return;
674 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500675 BMCWEB_LOG_ERROR << "Dump (DBus) doDelete respHandler got error "
676 << ec;
677 messages::internalError(asyncResp->res);
678 return;
679 }
680 };
681 crow::connections::systemBus->async_method_call(
682 respHandler, "xyz.openbmc_project.Dump.Manager",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500683 "/xyz/openbmc_project/dump/" +
684 std::string(boost::algorithm::to_lower_copy(dumpType)) + "/entry/" +
685 entryID,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500686 "xyz.openbmc_project.Object.Delete", "Delete");
687}
688
zhanghch058d1b46d2021-04-01 11:18:24 +0800689inline void
690 createDumpTaskCallback(const crow::Request& req,
691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
692 const uint32_t& dumpId, const std::string& dumpPath,
693 const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500694{
695 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500696 [dumpId, dumpPath, dumpType](
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500697 boost::system::error_code err, sdbusplus::message::message& m,
698 const std::shared_ptr<task::TaskData>& taskData) {
Ed Tanouscb13a392020-07-25 19:02:03 +0000699 if (err)
700 {
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500701 BMCWEB_LOG_ERROR << "Error in creating a dump";
702 taskData->state = "Cancelled";
703 return task::completed;
Ed Tanouscb13a392020-07-25 19:02:03 +0000704 }
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500705 std::vector<std::pair<
706 std::string,
707 std::vector<std::pair<std::string, std::variant<std::string>>>>>
708 interfacesList;
709
710 sdbusplus::message::object_path objPath;
711
712 m.read(objPath, interfacesList);
713
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500714 if (objPath.str ==
715 "/xyz/openbmc_project/dump/" +
716 std::string(boost::algorithm::to_lower_copy(dumpType)) +
717 "/entry/" + std::to_string(dumpId))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500718 {
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500719 nlohmann::json retMessage = messages::success();
720 taskData->messages.emplace_back(retMessage);
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500721
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500722 std::string headerLoc =
723 "Location: " + dumpPath + std::to_string(dumpId);
724 taskData->payload->httpHeaders.emplace_back(
725 std::move(headerLoc));
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500726
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500727 taskData->state = "Completed";
728 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500729 }
Asmitha Karunanithi6145ed62020-09-17 23:40:03 -0500730 return task::completed;
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500731 },
732 "type='signal',interface='org.freedesktop.DBus."
733 "ObjectManager',"
734 "member='InterfacesAdded', "
735 "path='/xyz/openbmc_project/dump'");
736
737 task->startTimer(std::chrono::minutes(3));
738 task->populateResp(asyncResp->res);
739 task->payload.emplace(req);
740}
741
zhanghch058d1b46d2021-04-01 11:18:24 +0800742inline void createDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
743 const crow::Request& req, const std::string& dumpType)
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500744{
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500745
746 std::string dumpPath;
747 if (dumpType == "BMC")
748 {
749 dumpPath = "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/";
750 }
751 else if (dumpType == "System")
752 {
753 dumpPath = "/redfish/v1/Systems/system/LogServices/Dump/Entries/";
754 }
755 else
756 {
757 BMCWEB_LOG_ERROR << "Invalid dump type: " << dumpType;
758 messages::internalError(asyncResp->res);
759 return;
760 }
761
762 std::optional<std::string> diagnosticDataType;
763 std::optional<std::string> oemDiagnosticDataType;
764
765 if (!redfish::json_util::readJson(
766 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
767 "OEMDiagnosticDataType", oemDiagnosticDataType))
768 {
769 return;
770 }
771
772 if (dumpType == "System")
773 {
774 if (!oemDiagnosticDataType || !diagnosticDataType)
775 {
776 BMCWEB_LOG_ERROR << "CreateDump action parameter "
777 "'DiagnosticDataType'/"
778 "'OEMDiagnosticDataType' value not found!";
779 messages::actionParameterMissing(
780 asyncResp->res, "CollectDiagnosticData",
781 "DiagnosticDataType & OEMDiagnosticDataType");
782 return;
783 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700784 if ((*oemDiagnosticDataType != "System") ||
785 (*diagnosticDataType != "OEM"))
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500786 {
787 BMCWEB_LOG_ERROR << "Wrong parameter values passed";
788 messages::invalidObject(asyncResp->res,
789 "System Dump creation parameters");
790 return;
791 }
792 }
793 else if (dumpType == "BMC")
794 {
795 if (!diagnosticDataType)
796 {
797 BMCWEB_LOG_ERROR << "CreateDump action parameter "
798 "'DiagnosticDataType' not found!";
799 messages::actionParameterMissing(
800 asyncResp->res, "CollectDiagnosticData", "DiagnosticDataType");
801 return;
802 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700803 if (*diagnosticDataType != "Manager")
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500804 {
805 BMCWEB_LOG_ERROR
806 << "Wrong parameter value passed for 'DiagnosticDataType'";
807 messages::invalidObject(asyncResp->res,
808 "BMC Dump creation parameters");
809 return;
810 }
811 }
812
813 crow::connections::systemBus->async_method_call(
814 [asyncResp, req, dumpPath, dumpType](const boost::system::error_code ec,
815 const uint32_t& dumpId) {
816 if (ec)
817 {
818 BMCWEB_LOG_ERROR << "CreateDump resp_handler got error " << ec;
819 messages::internalError(asyncResp->res);
820 return;
821 }
822 BMCWEB_LOG_DEBUG << "Dump Created. Id: " << dumpId;
823
824 createDumpTaskCallback(req, asyncResp, dumpId, dumpPath, dumpType);
825 },
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500826 "xyz.openbmc_project.Dump.Manager",
827 "/xyz/openbmc_project/dump/" +
828 std::string(boost::algorithm::to_lower_copy(dumpType)),
Asmitha Karunanithia43be802020-05-07 05:05:36 -0500829 "xyz.openbmc_project.Dump.Create", "CreateDump");
830}
831
zhanghch058d1b46d2021-04-01 11:18:24 +0800832inline void clearDump(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
833 const std::string& dumpType)
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500834{
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500835 std::string dumpTypeLowerCopy =
836 std::string(boost::algorithm::to_lower_copy(dumpType));
zhanghch058d1b46d2021-04-01 11:18:24 +0800837
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500838 crow::connections::systemBus->async_method_call(
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500839 [asyncResp, dumpType](const boost::system::error_code ec,
840 const std::vector<std::string>& subTreePaths) {
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500841 if (ec)
842 {
843 BMCWEB_LOG_ERROR << "resp_handler got error " << ec;
844 messages::internalError(asyncResp->res);
845 return;
846 }
847
848 for (const std::string& path : subTreePaths)
849 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000850 sdbusplus::message::object_path objPath(path);
851 std::string logID = objPath.filename();
852 if (logID.empty())
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500853 {
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000854 continue;
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500855 }
Ed Tanous2dfd18e2020-12-18 00:41:31 +0000856 deleteDumpEntry(asyncResp, logID, dumpType);
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500857 }
858 },
859 "xyz.openbmc_project.ObjectMapper",
860 "/xyz/openbmc_project/object_mapper",
861 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Asmitha Karunanithib47452b2020-09-25 02:02:19 -0500862 "/xyz/openbmc_project/dump/" + dumpTypeLowerCopy, 0,
863 std::array<std::string, 1>{"xyz.openbmc_project.Dump.Entry." +
864 dumpType});
Asmitha Karunanithi80319af2020-05-07 05:30:21 -0500865}
866
Ed Tanous2c70f802020-09-28 14:29:23 -0700867static void parseCrashdumpParameters(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500868 const std::vector<std::pair<std::string, VariantType>>& params,
869 std::string& filename, std::string& timestamp, std::string& logfile)
Johnathan Mantey043a0532020-03-10 17:15:28 -0700870{
871 for (auto property : params)
872 {
873 if (property.first == "Timestamp")
874 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500875 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500876 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700877 if (value != nullptr)
878 {
879 timestamp = *value;
880 }
881 }
882 else if (property.first == "Filename")
883 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500884 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500885 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700886 if (value != nullptr)
887 {
888 filename = *value;
889 }
890 }
891 else if (property.first == "Log")
892 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500893 const std::string* value =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500894 std::get_if<std::string>(&property.second);
Johnathan Mantey043a0532020-03-10 17:15:28 -0700895 if (value != nullptr)
896 {
897 logfile = *value;
898 }
899 }
900 }
901}
902
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500903constexpr char const* postCodeIface = "xyz.openbmc_project.State.Boot.PostCode";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800904class SystemLogServiceCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -0700905{
906 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700907 SystemLogServiceCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800908 Node(app, "/redfish/v1/Systems/system/LogServices/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800909 {
910 entityPrivileges = {
911 {boost::beast::http::verb::get, {{"Login"}}},
912 {boost::beast::http::verb::head, {{"Login"}}},
913 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
914 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
915 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
916 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
917 }
918
919 private:
920 /**
921 * Functions triggers appropriate requests on DBus
922 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800923 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
924 const crow::Request&, const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800925 {
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800926 // Collections don't include the static data added by SubRoute because
927 // it has a duplicate entry for members
928 asyncResp->res.jsonValue["@odata.type"] =
929 "#LogServiceCollection.LogServiceCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800930 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -0800931 "/redfish/v1/Systems/system/LogServices";
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800932 asyncResp->res.jsonValue["Name"] = "System Log Services Collection";
933 asyncResp->res.jsonValue["Description"] =
934 "Collection of LogServices for this Computer System";
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500935 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800936 logServiceArray = nlohmann::json::array();
Ed Tanous029573d2019-02-01 10:57:49 -0800937 logServiceArray.push_back(
938 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/EventLog"}});
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500939#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
raviteja-bc9bb6862020-02-03 11:53:32 -0600940 logServiceArray.push_back(
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -0500941 {{"@odata.id", "/redfish/v1/Systems/system/LogServices/Dump"}});
raviteja-bc9bb6862020-02-03 11:53:32 -0600942#endif
943
Jason M. Billsd53dd412019-02-12 17:16:22 -0800944#ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
945 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -0500946 {{"@odata.id",
947 "/redfish/v1/Systems/system/LogServices/Crashdump"}});
Jason M. Billsd53dd412019-02-12 17:16:22 -0800948#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800949 asyncResp->res.jsonValue["Members@odata.count"] =
950 logServiceArray.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800951
952 crow::connections::systemBus->async_method_call(
953 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500954 const std::vector<std::string>& subtreePath) {
ZhikuiRena3316fc2020-01-29 14:58:08 -0800955 if (ec)
956 {
957 BMCWEB_LOG_ERROR << ec;
958 return;
959 }
960
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500961 for (auto& pathStr : subtreePath)
ZhikuiRena3316fc2020-01-29 14:58:08 -0800962 {
963 if (pathStr.find("PostCode") != std::string::npos)
964 {
Ed Tanous23a21a12020-07-25 04:45:05 +0000965 nlohmann::json& logServiceArrayLocal =
ZhikuiRena3316fc2020-01-29 14:58:08 -0800966 asyncResp->res.jsonValue["Members"];
Ed Tanous23a21a12020-07-25 04:45:05 +0000967 logServiceArrayLocal.push_back(
ZhikuiRena3316fc2020-01-29 14:58:08 -0800968 {{"@odata.id", "/redfish/v1/Systems/system/"
969 "LogServices/PostCodes"}});
970 asyncResp->res.jsonValue["Members@odata.count"] =
Ed Tanous23a21a12020-07-25 04:45:05 +0000971 logServiceArrayLocal.size();
ZhikuiRena3316fc2020-01-29 14:58:08 -0800972 return;
973 }
974 }
975 },
976 "xyz.openbmc_project.ObjectMapper",
977 "/xyz/openbmc_project/object_mapper",
978 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500979 std::array<const char*, 1>{postCodeIface});
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800980 }
981};
982
983class EventLogService : public Node
984{
985 public:
Ed Tanous52cc1122020-07-18 13:51:21 -0700986 EventLogService(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -0800987 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -0800988 {
989 entityPrivileges = {
990 {boost::beast::http::verb::get, {{"Login"}}},
991 {boost::beast::http::verb::head, {{"Login"}}},
992 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
993 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
994 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
995 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
996 }
997
998 private:
zhanghch058d1b46d2021-04-01 11:18:24 +0800999 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1000 const crow::Request&, const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001001 {
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001002 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001003 "/redfish/v1/Systems/system/LogServices/EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001004 asyncResp->res.jsonValue["@odata.type"] =
1005 "#LogService.v1_1_0.LogService";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001006 asyncResp->res.jsonValue["Name"] = "Event Log Service";
1007 asyncResp->res.jsonValue["Description"] = "System Event Log Service";
Gunnar Mills73ec8302020-04-14 16:02:42 -05001008 asyncResp->res.jsonValue["Id"] = "EventLog";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001009 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
1010 asyncResp->res.jsonValue["Entries"] = {
1011 {"@odata.id",
Ed Tanous029573d2019-02-01 10:57:49 -08001012 "/redfish/v1/Systems/system/LogServices/EventLog/Entries"}};
Gunnar Millse7d6c8b2019-07-03 11:30:01 -05001013 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
1014
1015 {"target", "/redfish/v1/Systems/system/LogServices/EventLog/"
1016 "Actions/LogService.ClearLog"}};
Jason M. Bills489640c2019-05-17 09:56:36 -07001017 }
1018};
1019
Tim Lee1f56a3a2019-10-09 10:17:57 +08001020class JournalEventLogClear : public Node
Jason M. Bills489640c2019-05-17 09:56:36 -07001021{
1022 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001023 JournalEventLogClear(App& app) :
Jason M. Bills489640c2019-05-17 09:56:36 -07001024 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
1025 "LogService.ClearLog/")
1026 {
1027 entityPrivileges = {
1028 {boost::beast::http::verb::get, {{"Login"}}},
1029 {boost::beast::http::verb::head, {{"Login"}}},
1030 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1031 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1032 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1033 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1034 }
1035
1036 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001037 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1038 const crow::Request&, const std::vector<std::string>&) override
Jason M. Bills489640c2019-05-17 09:56:36 -07001039 {
Jason M. Bills489640c2019-05-17 09:56:36 -07001040
1041 // Clear the EventLog by deleting the log files
1042 std::vector<std::filesystem::path> redfishLogFiles;
1043 if (getRedfishLogFiles(redfishLogFiles))
1044 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001045 for (const std::filesystem::path& file : redfishLogFiles)
Jason M. Bills489640c2019-05-17 09:56:36 -07001046 {
1047 std::error_code ec;
1048 std::filesystem::remove(file, ec);
1049 }
1050 }
1051
1052 // Reload rsyslog so it knows to start new log files
1053 crow::connections::systemBus->async_method_call(
1054 [asyncResp](const boost::system::error_code ec) {
1055 if (ec)
1056 {
1057 BMCWEB_LOG_ERROR << "Failed to reload rsyslog: " << ec;
1058 messages::internalError(asyncResp->res);
1059 return;
1060 }
1061
1062 messages::success(asyncResp->res);
1063 },
1064 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
1065 "org.freedesktop.systemd1.Manager", "ReloadUnit", "rsyslog.service",
1066 "replace");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001067 }
1068};
1069
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001070static int fillEventLogEntryJson(const std::string& logEntryID,
Ed Tanousb5a76932020-09-29 16:16:58 -07001071 const std::string& logEntry,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001072 nlohmann::json& logEntryJson)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001073{
Jason M. Bills95820182019-04-22 16:25:34 -07001074 // The redfish log format is "<Timestamp> <MessageId>,<MessageArgs>"
Jason M. Billscd225da2019-05-08 15:31:57 -07001075 // First get the Timestamp
Ed Tanousf23b7292020-10-15 09:41:17 -07001076 size_t space = logEntry.find_first_of(' ');
Jason M. Billscd225da2019-05-08 15:31:57 -07001077 if (space == std::string::npos)
Jason M. Bills95820182019-04-22 16:25:34 -07001078 {
1079 return 1;
1080 }
Jason M. Billscd225da2019-05-08 15:31:57 -07001081 std::string timestamp = logEntry.substr(0, space);
1082 // Then get the log contents
Ed Tanousf23b7292020-10-15 09:41:17 -07001083 size_t entryStart = logEntry.find_first_not_of(' ', space);
Jason M. Billscd225da2019-05-08 15:31:57 -07001084 if (entryStart == std::string::npos)
1085 {
1086 return 1;
1087 }
1088 std::string_view entry(logEntry);
1089 entry.remove_prefix(entryStart);
1090 // Use split to separate the entry into its fields
1091 std::vector<std::string> logEntryFields;
1092 boost::split(logEntryFields, entry, boost::is_any_of(","),
1093 boost::token_compress_on);
1094 // We need at least a MessageId to be valid
1095 if (logEntryFields.size() < 1)
1096 {
1097 return 1;
1098 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001099 std::string& messageID = logEntryFields[0];
Jason M. Bills95820182019-04-22 16:25:34 -07001100
Jason M. Bills4851d452019-03-28 11:27:48 -07001101 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001102 const message_registries::Message* message =
Jason M. Bills4851d452019-03-28 11:27:48 -07001103 message_registries::getMessage(messageID);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001104
Jason M. Bills4851d452019-03-28 11:27:48 -07001105 std::string msg;
1106 std::string severity;
1107 if (message != nullptr)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001108 {
Jason M. Bills4851d452019-03-28 11:27:48 -07001109 msg = message->message;
1110 severity = message->severity;
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001111 }
1112
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001113 // Get the MessageArgs from the log if there are any
1114 boost::beast::span<std::string> messageArgs;
1115 if (logEntryFields.size() > 1)
Jason M. Bills4851d452019-03-28 11:27:48 -07001116 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001117 std::string& messageArgsStart = logEntryFields[1];
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001118 // If the first string is empty, assume there are no MessageArgs
1119 std::size_t messageArgsSize = 0;
1120 if (!messageArgsStart.empty())
Jason M. Bills4851d452019-03-28 11:27:48 -07001121 {
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001122 messageArgsSize = logEntryFields.size() - 1;
1123 }
1124
Ed Tanous23a21a12020-07-25 04:45:05 +00001125 messageArgs = {&messageArgsStart, messageArgsSize};
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001126
1127 // Fill the MessageArgs into the Message
1128 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001129 for (const std::string& messageArg : messageArgs)
Jason M. Bills15a86ff2019-06-18 13:49:54 -07001130 {
1131 std::string argStr = "%" + std::to_string(++i);
1132 size_t argPos = msg.find(argStr);
1133 if (argPos != std::string::npos)
1134 {
1135 msg.replace(argPos, argStr.length(), messageArg);
1136 }
Jason M. Bills4851d452019-03-28 11:27:48 -07001137 }
1138 }
1139
Jason M. Bills95820182019-04-22 16:25:34 -07001140 // Get the Created time from the timestamp. The log timestamp is in RFC3339
1141 // format which matches the Redfish format except for the fractional seconds
1142 // between the '.' and the '+', so just remove them.
Ed Tanousf23b7292020-10-15 09:41:17 -07001143 std::size_t dot = timestamp.find_first_of('.');
1144 std::size_t plus = timestamp.find_first_of('+');
Jason M. Bills95820182019-04-22 16:25:34 -07001145 if (dot != std::string::npos && plus != std::string::npos)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001146 {
Jason M. Bills95820182019-04-22 16:25:34 -07001147 timestamp.erase(dot, plus - dot);
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001148 }
1149
1150 // Fill in the log entry with the gathered data
Jason M. Bills95820182019-04-22 16:25:34 -07001151 logEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001152 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Ed Tanous029573d2019-02-01 10:57:49 -08001153 {"@odata.id",
Jason M. Bills897967d2019-07-29 17:05:30 -07001154 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
Jason M. Bills95820182019-04-22 16:25:34 -07001155 logEntryID},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001156 {"Name", "System Event Log Entry"},
Jason M. Bills95820182019-04-22 16:25:34 -07001157 {"Id", logEntryID},
1158 {"Message", std::move(msg)},
1159 {"MessageId", std::move(messageID)},
Ed Tanousf23b7292020-10-15 09:41:17 -07001160 {"MessageArgs", messageArgs},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001161 {"EntryType", "Event"},
Jason M. Bills95820182019-04-22 16:25:34 -07001162 {"Severity", std::move(severity)},
1163 {"Created", std::move(timestamp)}};
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001164 return 0;
1165}
1166
Anthony Wilson27062602019-04-22 02:10:09 -05001167class JournalEventLogEntryCollection : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001168{
1169 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001170 JournalEventLogEntryCollection(App& app) :
Ed Tanous029573d2019-02-01 10:57:49 -08001171 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001172 {
1173 entityPrivileges = {
1174 {boost::beast::http::verb::get, {{"Login"}}},
1175 {boost::beast::http::verb::head, {{"Login"}}},
1176 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1177 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1178 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1179 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1180 }
1181
1182 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001183 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1184 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00001185 const std::vector<std::string>&) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001186 {
Ed Tanous271584a2019-07-09 16:24:22 -07001187 uint64_t skip = 0;
1188 uint64_t top = maxEntriesPerPage; // Show max entries by default
zhanghch058d1b46d2021-04-01 11:18:24 +08001189 if (!getSkipParam(asyncResp, req, skip))
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001190 {
1191 return;
1192 }
zhanghch058d1b46d2021-04-01 11:18:24 +08001193 if (!getTopParam(asyncResp, req, top))
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001194 {
1195 return;
1196 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001197 // Collections don't include the static data added by SubRoute because
1198 // it has a duplicate entry for members
1199 asyncResp->res.jsonValue["@odata.type"] =
1200 "#LogEntryCollection.LogEntryCollection";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001201 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanous029573d2019-02-01 10:57:49 -08001202 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001203 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1204 asyncResp->res.jsonValue["Description"] =
1205 "Collection of System Event Log Entries";
Andrew Geisslercb92c032018-08-17 07:56:14 -07001206
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001207 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001208 logEntryArray = nlohmann::json::array();
Jason M. Bills95820182019-04-22 16:25:34 -07001209 // Go through the log files and create a unique ID for each entry
1210 std::vector<std::filesystem::path> redfishLogFiles;
1211 getRedfishLogFiles(redfishLogFiles);
Ed Tanousb01bf292019-03-25 19:25:26 +00001212 uint64_t entryCount = 0;
Jason M. Billscd225da2019-05-08 15:31:57 -07001213 std::string logEntry;
Jason M. Bills95820182019-04-22 16:25:34 -07001214
1215 // Oldest logs are in the last file, so start there and loop backwards
Jason M. Billscd225da2019-05-08 15:31:57 -07001216 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1217 it++)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001218 {
Jason M. Billscd225da2019-05-08 15:31:57 -07001219 std::ifstream logStream(*it);
Jason M. Bills95820182019-04-22 16:25:34 -07001220 if (!logStream.is_open())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001221 {
1222 continue;
1223 }
1224
Jason M. Billse85d6b12019-07-29 17:01:15 -07001225 // Reset the unique ID on the first entry
1226 bool firstEntry = true;
Jason M. Bills95820182019-04-22 16:25:34 -07001227 while (std::getline(logStream, logEntry))
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001228 {
Jason M. Bills95820182019-04-22 16:25:34 -07001229 entryCount++;
1230 // Handle paging using skip (number of entries to skip from the
1231 // start) and top (number of entries to display)
1232 if (entryCount <= skip || entryCount > skip + top)
1233 {
1234 continue;
1235 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001236
Jason M. Bills95820182019-04-22 16:25:34 -07001237 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07001238 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
Jason M. Bills95820182019-04-22 16:25:34 -07001239 {
1240 continue;
1241 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001242
Jason M. Billse85d6b12019-07-29 17:01:15 -07001243 if (firstEntry)
1244 {
1245 firstEntry = false;
1246 }
1247
Jason M. Bills95820182019-04-22 16:25:34 -07001248 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001249 nlohmann::json& bmcLogEntry = logEntryArray.back();
Jason M. Bills95820182019-04-22 16:25:34 -07001250 if (fillEventLogEntryJson(idStr, logEntry, bmcLogEntry) != 0)
1251 {
1252 messages::internalError(asyncResp->res);
1253 return;
1254 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001255 }
1256 }
1257 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
1258 if (skip + top < entryCount)
1259 {
1260 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Bills95820182019-04-22 16:25:34 -07001261 "/redfish/v1/Systems/system/LogServices/EventLog/"
1262 "Entries?$skip=" +
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001263 std::to_string(skip + top);
1264 }
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001265 }
1266};
1267
Jason M. Bills897967d2019-07-29 17:05:30 -07001268class JournalEventLogEntry : public Node
1269{
1270 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001271 JournalEventLogEntry(App& app) :
Jason M. Bills897967d2019-07-29 17:05:30 -07001272 Node(app,
1273 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1274 std::string())
1275 {
1276 entityPrivileges = {
1277 {boost::beast::http::verb::get, {{"Login"}}},
1278 {boost::beast::http::verb::head, {{"Login"}}},
1279 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1280 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1281 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1282 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1283 }
1284
1285 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001286 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1287 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001288 const std::vector<std::string>& params) override
Jason M. Bills897967d2019-07-29 17:05:30 -07001289 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001290
Jason M. Bills897967d2019-07-29 17:05:30 -07001291 if (params.size() != 1)
1292 {
1293 messages::internalError(asyncResp->res);
1294 return;
1295 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001296 const std::string& targetID = params[0];
Jason M. Bills897967d2019-07-29 17:05:30 -07001297
1298 // Go through the log files and check the unique ID for each entry to
1299 // find the target entry
1300 std::vector<std::filesystem::path> redfishLogFiles;
1301 getRedfishLogFiles(redfishLogFiles);
1302 std::string logEntry;
1303
1304 // Oldest logs are in the last file, so start there and loop backwards
1305 for (auto it = redfishLogFiles.rbegin(); it < redfishLogFiles.rend();
1306 it++)
1307 {
1308 std::ifstream logStream(*it);
1309 if (!logStream.is_open())
1310 {
1311 continue;
1312 }
1313
1314 // Reset the unique ID on the first entry
1315 bool firstEntry = true;
1316 while (std::getline(logStream, logEntry))
1317 {
1318 std::string idStr;
1319 if (!getUniqueEntryID(logEntry, idStr, firstEntry))
1320 {
1321 continue;
1322 }
1323
1324 if (firstEntry)
1325 {
1326 firstEntry = false;
1327 }
1328
1329 if (idStr == targetID)
1330 {
1331 if (fillEventLogEntryJson(idStr, logEntry,
1332 asyncResp->res.jsonValue) != 0)
1333 {
1334 messages::internalError(asyncResp->res);
1335 return;
1336 }
1337 return;
1338 }
1339 }
1340 }
1341 // Requested ID was not found
1342 messages::resourceMissingAtURI(asyncResp->res, targetID);
1343 }
1344};
1345
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001346class DBusEventLogEntryCollection : public Node
1347{
1348 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001349 DBusEventLogEntryCollection(App& app) :
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001350 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Entries/")
1351 {
1352 entityPrivileges = {
1353 {boost::beast::http::verb::get, {{"Login"}}},
1354 {boost::beast::http::verb::head, {{"Login"}}},
1355 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1356 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1357 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1358 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1359 }
1360
1361 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001362 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1363 const crow::Request&, const std::vector<std::string>&) override
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001364 {
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001365
1366 // Collections don't include the static data added by SubRoute because
1367 // it has a duplicate entry for members
1368 asyncResp->res.jsonValue["@odata.type"] =
1369 "#LogEntryCollection.LogEntryCollection";
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001370 asyncResp->res.jsonValue["@odata.id"] =
1371 "/redfish/v1/Systems/system/LogServices/EventLog/Entries";
1372 asyncResp->res.jsonValue["Name"] = "System Event Log Entries";
1373 asyncResp->res.jsonValue["Description"] =
1374 "Collection of System Event Log Entries";
1375
Andrew Geisslercb92c032018-08-17 07:56:14 -07001376 // DBus implementation of EventLog/Entries
1377 // Make call to Logging Service to find all log entry objects
1378 crow::connections::systemBus->async_method_call(
1379 [asyncResp](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001380 GetManagedObjectsType& resp) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001381 if (ec)
1382 {
1383 // TODO Handle for specific error code
1384 BMCWEB_LOG_ERROR
1385 << "getLogEntriesIfaceData resp_handler got error "
1386 << ec;
1387 messages::internalError(asyncResp->res);
1388 return;
1389 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001390 nlohmann::json& entriesArray =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001391 asyncResp->res.jsonValue["Members"];
1392 entriesArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001393 for (auto& objectPath : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001394 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001395 uint32_t* id = nullptr;
1396 std::time_t timestamp{};
1397 std::time_t updateTimestamp{};
1398 std::string* severity = nullptr;
1399 std::string* message = nullptr;
1400 std::string* filePath = nullptr;
1401 bool resolved = false;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001402 for (auto& interfaceMap : objectPath.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001403 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001404 if (interfaceMap.first ==
Andrew Geisslercb92c032018-08-17 07:56:14 -07001405 "xyz.openbmc_project.Logging.Entry")
1406 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001407 for (auto& propertyMap : interfaceMap.second)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001408 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001409 if (propertyMap.first == "Id")
George Liuebd45902020-08-26 14:21:10 +08001410 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001411 id = std::get_if<uint32_t>(
1412 &propertyMap.second);
George Liuebd45902020-08-26 14:21:10 +08001413 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001414 else if (propertyMap.first == "Timestamp")
George Liuebd45902020-08-26 14:21:10 +08001415 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001416 const uint64_t* millisTimeStamp =
1417 std::get_if<uint64_t>(
1418 &propertyMap.second);
1419 if (millisTimeStamp != nullptr)
1420 {
1421 timestamp = crow::utility::getTimestamp(
George Liuebd45902020-08-26 14:21:10 +08001422 *millisTimeStamp);
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001423 }
George Liuebd45902020-08-26 14:21:10 +08001424 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001425 else if (propertyMap.first == "UpdateTimestamp")
Xiaochao Ma75710de2021-01-21 17:56:02 +08001426 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001427 const uint64_t* millisTimeStamp =
1428 std::get_if<uint64_t>(
1429 &propertyMap.second);
1430 if (millisTimeStamp != nullptr)
1431 {
1432 updateTimestamp =
1433 crow::utility::getTimestamp(
1434 *millisTimeStamp);
1435 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001436 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001437 else if (propertyMap.first == "Severity")
1438 {
1439 severity = std::get_if<std::string>(
1440 &propertyMap.second);
1441 }
1442 else if (propertyMap.first == "Message")
1443 {
1444 message = std::get_if<std::string>(
1445 &propertyMap.second);
1446 }
1447 else if (propertyMap.first == "Resolved")
1448 {
1449 bool* resolveptr =
1450 std::get_if<bool>(&propertyMap.second);
1451 if (resolveptr == nullptr)
1452 {
1453 messages::internalError(asyncResp->res);
1454 return;
1455 }
1456 resolved = *resolveptr;
1457 }
1458 }
1459 if (id == nullptr || message == nullptr ||
1460 severity == nullptr)
1461 {
1462 messages::internalError(asyncResp->res);
1463 return;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001464 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001465 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001466 else if (interfaceMap.first ==
1467 "xyz.openbmc_project.Common.FilePath")
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001468 {
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001469 for (auto& propertyMap : interfaceMap.second)
1470 {
1471 if (propertyMap.first == "Path")
1472 {
1473 filePath = std::get_if<std::string>(
1474 &propertyMap.second);
1475 }
1476 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001477 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001478 }
1479 // Object path without the xyz.openbmc_project.Logging.Entry
1480 // interface, ignore and continue.
1481 if (id == nullptr || message == nullptr ||
1482 severity == nullptr)
1483 {
1484 continue;
1485 }
1486 entriesArray.push_back({});
1487 nlohmann::json& thisEntry = entriesArray.back();
1488 thisEntry["@odata.type"] = "#LogEntry.v1_8_0.LogEntry";
1489 thisEntry["@odata.id"] = "/redfish/v1/Systems/system/"
1490 "LogServices/EventLog/Entries/" +
1491 std::to_string(*id);
1492 thisEntry["Name"] = "System Event Log Entry";
1493 thisEntry["Id"] = std::to_string(*id);
1494 thisEntry["Message"] = *message;
1495 thisEntry["Resolved"] = resolved;
1496 thisEntry["EntryType"] = "Event";
1497 thisEntry["Severity"] =
1498 translateSeverityDbusToRedfish(*severity);
1499 thisEntry["Created"] =
1500 crow::utility::getDateTime(timestamp);
1501 thisEntry["Modified"] =
1502 crow::utility::getDateTime(updateTimestamp);
1503 if (filePath != nullptr)
1504 {
1505 thisEntry["AdditionalDataURI"] =
1506 "/redfish/v1/Systems/system/LogServices/EventLog/"
Abhishek Patelde8d94a2021-05-13 22:57:36 -05001507 "Entries/" +
1508 std::to_string(*id) + "/attachment";
Andrew Geisslercb92c032018-08-17 07:56:14 -07001509 }
1510 }
1511 std::sort(entriesArray.begin(), entriesArray.end(),
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001512 [](const nlohmann::json& left,
1513 const nlohmann::json& right) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07001514 return (left["Id"] <= right["Id"]);
1515 });
1516 asyncResp->res.jsonValue["Members@odata.count"] =
1517 entriesArray.size();
1518 },
1519 "xyz.openbmc_project.Logging", "/xyz/openbmc_project/logging",
1520 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001521 }
1522};
1523
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001524class DBusEventLogEntry : public Node
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001525{
1526 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001527 DBusEventLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001528 Node(app,
Ed Tanous029573d2019-02-01 10:57:49 -08001529 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/",
1530 std::string())
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001531 {
1532 entityPrivileges = {
1533 {boost::beast::http::verb::get, {{"Login"}}},
1534 {boost::beast::http::verb::head, {{"Login"}}},
1535 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1536 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1537 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1538 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1539 }
1540
1541 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001542 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1543 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001544 const std::vector<std::string>& params) override
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001545 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001546
Ed Tanous029573d2019-02-01 10:57:49 -08001547 if (params.size() != 1)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001548 {
1549 messages::internalError(asyncResp->res);
1550 return;
1551 }
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001552 std::string entryID = params[0];
1553 dbus::utility::escapePathForDbus(entryID);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001554
Andrew Geisslercb92c032018-08-17 07:56:14 -07001555 // DBus implementation of EventLog/Entries
1556 // Make call to Logging Service to find all log entry objects
1557 crow::connections::systemBus->async_method_call(
1558 [asyncResp, entryID](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001559 GetManagedPropertyType& resp) {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001560 if (ec.value() == EBADR)
1561 {
1562 messages::resourceNotFound(asyncResp->res, "EventLogEntry",
1563 entryID);
1564 return;
1565 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001566 if (ec)
1567 {
1568 BMCWEB_LOG_ERROR
1569 << "EventLogEntry (DBus) resp_handler got error " << ec;
1570 messages::internalError(asyncResp->res);
1571 return;
1572 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001573 uint32_t* id = nullptr;
Ed Tanous66664f22019-10-11 13:05:49 -07001574 std::time_t timestamp{};
George Liud139c232020-08-18 18:48:57 +08001575 std::time_t updateTimestamp{};
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001576 std::string* severity = nullptr;
1577 std::string* message = nullptr;
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001578 std::string* filePath = nullptr;
Xiaochao Ma75710de2021-01-21 17:56:02 +08001579 bool resolved = false;
George Liud139c232020-08-18 18:48:57 +08001580
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001581 for (auto& propertyMap : resp)
Andrew Geisslercb92c032018-08-17 07:56:14 -07001582 {
1583 if (propertyMap.first == "Id")
1584 {
1585 id = std::get_if<uint32_t>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001586 }
1587 else if (propertyMap.first == "Timestamp")
1588 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001589 const uint64_t* millisTimeStamp =
Andrew Geisslercb92c032018-08-17 07:56:14 -07001590 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001591 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001592 {
1593 timestamp =
1594 crow::utility::getTimestamp(*millisTimeStamp);
1595 }
George Liud139c232020-08-18 18:48:57 +08001596 }
1597 else if (propertyMap.first == "UpdateTimestamp")
1598 {
1599 const uint64_t* millisTimeStamp =
1600 std::get_if<uint64_t>(&propertyMap.second);
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001601 if (millisTimeStamp != nullptr)
George Liuebd45902020-08-26 14:21:10 +08001602 {
1603 updateTimestamp =
1604 crow::utility::getTimestamp(*millisTimeStamp);
1605 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001606 }
1607 else if (propertyMap.first == "Severity")
1608 {
1609 severity =
1610 std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001611 }
1612 else if (propertyMap.first == "Message")
1613 {
1614 message = std::get_if<std::string>(&propertyMap.second);
Andrew Geisslercb92c032018-08-17 07:56:14 -07001615 }
Xiaochao Ma75710de2021-01-21 17:56:02 +08001616 else if (propertyMap.first == "Resolved")
1617 {
1618 bool* resolveptr =
1619 std::get_if<bool>(&propertyMap.second);
1620 if (resolveptr == nullptr)
1621 {
1622 messages::internalError(asyncResp->res);
1623 return;
1624 }
1625 resolved = *resolveptr;
1626 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001627 else if (propertyMap.first == "Path")
1628 {
1629 filePath =
1630 std::get_if<std::string>(&propertyMap.second);
1631 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001632 }
Ed Tanous271584a2019-07-09 16:24:22 -07001633 if (id == nullptr || message == nullptr || severity == nullptr)
1634 {
Adriana Kobylakae34c8e2021-02-11 09:33:10 -06001635 messages::internalError(asyncResp->res);
Ed Tanous271584a2019-07-09 16:24:22 -07001636 return;
1637 }
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001638 asyncResp->res.jsonValue["@odata.type"] =
1639 "#LogEntry.v1_8_0.LogEntry";
1640 asyncResp->res.jsonValue["@odata.id"] =
1641 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/" +
1642 std::to_string(*id);
1643 asyncResp->res.jsonValue["Name"] = "System Event Log Entry";
1644 asyncResp->res.jsonValue["Id"] = std::to_string(*id);
1645 asyncResp->res.jsonValue["Message"] = *message;
1646 asyncResp->res.jsonValue["Resolved"] = resolved;
1647 asyncResp->res.jsonValue["EntryType"] = "Event";
1648 asyncResp->res.jsonValue["Severity"] =
1649 translateSeverityDbusToRedfish(*severity);
1650 asyncResp->res.jsonValue["Created"] =
1651 crow::utility::getDateTime(timestamp);
1652 asyncResp->res.jsonValue["Modified"] =
1653 crow::utility::getDateTime(updateTimestamp);
1654 if (filePath != nullptr)
1655 {
1656 asyncResp->res.jsonValue["AdditionalDataURI"] =
1657 "/redfish/v1/Systems/system/LogServices/EventLog/"
Abhishek Patelde8d94a2021-05-13 22:57:36 -05001658 "Entries/" +
1659 std::to_string(*id) + "/attachment";
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001660 }
Andrew Geisslercb92c032018-08-17 07:56:14 -07001661 },
1662 "xyz.openbmc_project.Logging",
1663 "/xyz/openbmc_project/logging/entry/" + entryID,
Adriana Kobylakf86bb902021-01-11 11:11:05 -06001664 "org.freedesktop.DBus.Properties", "GetAll", "");
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001665 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001666
zhanghch058d1b46d2021-04-01 11:18:24 +08001667 void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1668 const crow::Request& req,
Xiaochao Ma75710de2021-01-21 17:56:02 +08001669 const std::vector<std::string>& params) override
1670 {
Xiaochao Ma75710de2021-01-21 17:56:02 +08001671
1672 if (params.size() != 1)
1673 {
1674 messages::internalError(asyncResp->res);
1675 return;
1676 }
1677 std::string entryId = params[0];
1678
1679 std::optional<bool> resolved;
1680
zhanghch058d1b46d2021-04-01 11:18:24 +08001681 if (!json_util::readJson(req, asyncResp->res, "Resolved", resolved))
Xiaochao Ma75710de2021-01-21 17:56:02 +08001682 {
1683 return;
1684 }
1685
1686 if (resolved)
1687 {
1688 BMCWEB_LOG_DEBUG << "Set Resolved";
1689
1690 crow::connections::systemBus->async_method_call(
1691 [asyncResp, resolved,
1692 entryId](const boost::system::error_code ec) {
1693 if (ec)
1694 {
1695 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1696 messages::internalError(asyncResp->res);
1697 return;
1698 }
1699 },
1700 "xyz.openbmc_project.Logging",
1701 "/xyz/openbmc_project/logging/entry/" + entryId,
1702 "org.freedesktop.DBus.Properties", "Set",
1703 "xyz.openbmc_project.Logging.Entry", "Resolved",
1704 std::variant<bool>(*resolved));
1705 }
1706 }
1707
zhanghch058d1b46d2021-04-01 11:18:24 +08001708 void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1709 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001710 const std::vector<std::string>& params) override
Chicago Duan336e96c2019-07-15 14:22:08 +08001711 {
1712
1713 BMCWEB_LOG_DEBUG << "Do delete single event entries.";
1714
Chicago Duan336e96c2019-07-15 14:22:08 +08001715 if (params.size() != 1)
1716 {
1717 messages::internalError(asyncResp->res);
1718 return;
1719 }
1720 std::string entryID = params[0];
1721
1722 dbus::utility::escapePathForDbus(entryID);
1723
1724 // Process response from Logging service.
George Liu3de8d8b2021-03-22 17:49:39 +08001725 auto respHandler = [asyncResp,
1726 entryID](const boost::system::error_code ec) {
Chicago Duan336e96c2019-07-15 14:22:08 +08001727 BMCWEB_LOG_DEBUG << "EventLogEntry (DBus) doDelete callback: Done";
1728 if (ec)
1729 {
George Liu3de8d8b2021-03-22 17:49:39 +08001730 if (ec.value() == EBADR)
1731 {
1732 messages::resourceNotFound(asyncResp->res, "LogEntry",
1733 entryID);
1734 return;
1735 }
Chicago Duan336e96c2019-07-15 14:22:08 +08001736 // TODO Handle for specific error code
1737 BMCWEB_LOG_ERROR
1738 << "EventLogEntry (DBus) doDelete respHandler got error "
1739 << ec;
1740 asyncResp->res.result(
1741 boost::beast::http::status::internal_server_error);
1742 return;
1743 }
1744
1745 asyncResp->res.result(boost::beast::http::status::ok);
1746 };
1747
1748 // Make call to Logging service to request Delete Log
1749 crow::connections::systemBus->async_method_call(
1750 respHandler, "xyz.openbmc_project.Logging",
1751 "/xyz/openbmc_project/logging/entry/" + entryID,
1752 "xyz.openbmc_project.Object.Delete", "Delete");
1753 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001754};
1755
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001756class DBusEventLogEntryDownload : public Node
1757{
1758 public:
1759 DBusEventLogEntryDownload(App& app) :
Abhishek Patelde8d94a2021-05-13 22:57:36 -05001760 Node(app,
1761 "/redfish/v1/Systems/system/LogServices/EventLog/Entries/<str>/"
1762 "attachment",
1763 std::string())
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001764 {
1765 entityPrivileges = {
1766 {boost::beast::http::verb::get, {{"Login"}}},
1767 {boost::beast::http::verb::head, {{"Login"}}},
1768 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1769 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1770 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1771 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1772 }
1773
1774 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001775 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1776 const crow::Request& req,
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001777 const std::vector<std::string>& params) override
1778 {
Adriana Kobylak400fd1f2021-01-29 09:01:30 -06001779 if (params.size() != 1)
1780 {
1781 messages::internalError(asyncResp->res);
1782 return;
1783 }
1784
1785 std::string_view acceptHeader = req.getHeaderValue("Accept");
1786 // The iterators in boost/http/rfc7230.hpp end the string if '/' is
1787 // found, so replace it with arbitrary character '|' which is not part
1788 // of the Accept header syntax.
1789 std::string acceptStr =
1790 boost::replace_all_copy(std::string(acceptHeader), "/", "|");
1791 boost::beast::http::ext_list acceptTypes{acceptStr};
1792 bool supported = false;
1793 for (const auto& type : acceptTypes)
1794 {
1795 if ((type.first == "*|*") ||
1796 (type.first == "application|octet-stream"))
1797 {
1798 supported = true;
1799 break;
1800 }
1801 }
1802 if (!supported)
1803 {
1804 asyncResp->res.result(boost::beast::http::status::bad_request);
1805 return;
1806 }
1807
1808 std::string entryID = params[0];
1809 dbus::utility::escapePathForDbus(entryID);
1810
1811 crow::connections::systemBus->async_method_call(
1812 [asyncResp, entryID](const boost::system::error_code ec,
1813 const sdbusplus::message::unix_fd& unixfd) {
1814 if (ec.value() == EBADR)
1815 {
1816 messages::resourceNotFound(asyncResp->res,
1817 "EventLogAttachment", entryID);
1818 return;
1819 }
1820 if (ec)
1821 {
1822 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1823 messages::internalError(asyncResp->res);
1824 return;
1825 }
1826
1827 int fd = -1;
1828 fd = dup(unixfd);
1829 if (fd == -1)
1830 {
1831 messages::internalError(asyncResp->res);
1832 return;
1833 }
1834
1835 long long int size = lseek(fd, 0, SEEK_END);
1836 if (size == -1)
1837 {
1838 messages::internalError(asyncResp->res);
1839 return;
1840 }
1841
1842 // Arbitrary max size of 64kb
1843 constexpr int maxFileSize = 65536;
1844 if (size > maxFileSize)
1845 {
1846 BMCWEB_LOG_ERROR
1847 << "File size exceeds maximum allowed size of "
1848 << maxFileSize;
1849 messages::internalError(asyncResp->res);
1850 return;
1851 }
1852 std::vector<char> data(static_cast<size_t>(size));
1853 long long int rc = lseek(fd, 0, SEEK_SET);
1854 if (rc == -1)
1855 {
1856 messages::internalError(asyncResp->res);
1857 return;
1858 }
1859 rc = read(fd, data.data(), data.size());
1860 if ((rc == -1) || (rc != size))
1861 {
1862 messages::internalError(asyncResp->res);
1863 return;
1864 }
1865 close(fd);
1866
1867 std::string_view strData(data.data(), data.size());
1868 std::string output = crow::utility::base64encode(strData);
1869
1870 asyncResp->res.addHeader("Content-Type",
1871 "application/octet-stream");
1872 asyncResp->res.addHeader("Content-Transfer-Encoding", "Base64");
1873 asyncResp->res.body() = std::move(output);
1874 },
1875 "xyz.openbmc_project.Logging",
1876 "/xyz/openbmc_project/logging/entry/" + entryID,
1877 "xyz.openbmc_project.Logging.Entry", "GetEntry");
1878 }
1879};
1880
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001881class BMCLogServiceCollection : public Node
1882{
1883 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001884 BMCLogServiceCollection(App& app) :
Ed Tanous4ed77cd2018-10-15 08:08:07 -07001885 Node(app, "/redfish/v1/Managers/bmc/LogServices/")
Ed Tanous1da66f72018-07-27 16:13:37 -07001886 {
Ed Tanous1da66f72018-07-27 16:13:37 -07001887 entityPrivileges = {
Jason M. Billse1f26342018-07-18 12:12:00 -07001888 {boost::beast::http::verb::get, {{"Login"}}},
1889 {boost::beast::http::verb::head, {{"Login"}}},
1890 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1891 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1892 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1893 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07001894 }
1895
1896 private:
1897 /**
1898 * Functions triggers appropriate requests on DBus
1899 */
zhanghch058d1b46d2021-04-01 11:18:24 +08001900 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1901 const crow::Request&, const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07001902 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001903
Ed Tanous1da66f72018-07-27 16:13:37 -07001904 // Collections don't include the static data added by SubRoute because
1905 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07001906 asyncResp->res.jsonValue["@odata.type"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001907 "#LogServiceCollection.LogServiceCollection";
Jason M. Billse1f26342018-07-18 12:12:00 -07001908 asyncResp->res.jsonValue["@odata.id"] =
1909 "/redfish/v1/Managers/bmc/LogServices";
1910 asyncResp->res.jsonValue["Name"] = "Open BMC Log Services Collection";
1911 asyncResp->res.jsonValue["Description"] =
Ed Tanous1da66f72018-07-27 16:13:37 -07001912 "Collection of LogServices for this Manager";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001913 nlohmann::json& logServiceArray = asyncResp->res.jsonValue["Members"];
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001914 logServiceArray = nlohmann::json::array();
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05001915#ifdef BMCWEB_ENABLE_REDFISH_DUMP_LOG
1916 logServiceArray.push_back(
1917 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump"}});
1918#endif
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001919#ifdef BMCWEB_ENABLE_REDFISH_BMC_JOURNAL
1920 logServiceArray.push_back(
Anthony Wilson08a4e4b2019-04-12 08:23:05 -05001921 {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal"}});
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001922#endif
Jason M. Billse1f26342018-07-18 12:12:00 -07001923 asyncResp->res.jsonValue["Members@odata.count"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001924 logServiceArray.size();
Ed Tanous1da66f72018-07-27 16:13:37 -07001925 }
1926};
1927
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001928class BMCJournalLogService : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07001929{
1930 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07001931 BMCJournalLogService(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001932 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/")
Jason M. Billse1f26342018-07-18 12:12:00 -07001933 {
Jason M. Billse1f26342018-07-18 12:12:00 -07001934 entityPrivileges = {
1935 {boost::beast::http::verb::get, {{"Login"}}},
1936 {boost::beast::http::verb::head, {{"Login"}}},
1937 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
1938 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
1939 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
1940 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
1941 }
1942
1943 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08001944 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1945 const crow::Request&, const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07001946 {
zhanghch058d1b46d2021-04-01 11:18:24 +08001947
Jason M. Billse1f26342018-07-18 12:12:00 -07001948 asyncResp->res.jsonValue["@odata.type"] =
1949 "#LogService.v1_1_0.LogService";
Ed Tanous0f74e642018-11-12 15:17:05 -08001950 asyncResp->res.jsonValue["@odata.id"] =
1951 "/redfish/v1/Managers/bmc/LogServices/Journal";
Jason M. Billsc4bf6372018-11-05 13:48:27 -08001952 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Log Service";
1953 asyncResp->res.jsonValue["Description"] = "BMC Journal Log Service";
1954 asyncResp->res.jsonValue["Id"] = "BMC Journal";
Jason M. Billse1f26342018-07-18 12:12:00 -07001955 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
Jason M. Billscd50aa42019-02-12 17:09:02 -08001956 asyncResp->res.jsonValue["Entries"] = {
1957 {"@odata.id",
Ed Tanous086be232019-05-23 11:47:09 -07001958 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07001959 }
1960};
1961
Gunnar Mills1214b7e2020-06-04 10:11:30 -05001962static int fillBMCJournalLogEntryJson(const std::string& bmcJournalLogEntryID,
1963 sd_journal* journal,
1964 nlohmann::json& bmcJournalLogEntryJson)
Jason M. Billse1f26342018-07-18 12:12:00 -07001965{
1966 // Get the Log Entry contents
1967 int ret = 0;
Jason M. Billse1f26342018-07-18 12:12:00 -07001968
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001969 std::string message;
1970 std::string_view syslogID;
1971 ret = getJournalMetadata(journal, "SYSLOG_IDENTIFIER", syslogID);
1972 if (ret < 0)
1973 {
1974 BMCWEB_LOG_ERROR << "Failed to read SYSLOG_IDENTIFIER field: "
1975 << strerror(-ret);
1976 }
1977 if (!syslogID.empty())
1978 {
1979 message += std::string(syslogID) + ": ";
1980 }
1981
Ed Tanous39e77502019-03-04 17:35:53 -08001982 std::string_view msg;
Jason M. Bills16428a12018-11-02 12:42:29 -07001983 ret = getJournalMetadata(journal, "MESSAGE", msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001984 if (ret < 0)
1985 {
1986 BMCWEB_LOG_ERROR << "Failed to read MESSAGE field: " << strerror(-ret);
1987 return 1;
1988 }
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08001989 message += std::string(msg);
Jason M. Billse1f26342018-07-18 12:12:00 -07001990
1991 // Get the severity from the PRIORITY field
Ed Tanous271584a2019-07-09 16:24:22 -07001992 long int severity = 8; // Default to an invalid priority
Jason M. Bills16428a12018-11-02 12:42:29 -07001993 ret = getJournalMetadata(journal, "PRIORITY", 10, severity);
Jason M. Billse1f26342018-07-18 12:12:00 -07001994 if (ret < 0)
1995 {
1996 BMCWEB_LOG_ERROR << "Failed to read PRIORITY field: " << strerror(-ret);
Jason M. Billse1f26342018-07-18 12:12:00 -07001997 }
Jason M. Billse1f26342018-07-18 12:12:00 -07001998
1999 // Get the Created time from the timestamp
Jason M. Bills16428a12018-11-02 12:42:29 -07002000 std::string entryTimeStr;
2001 if (!getEntryTimestamp(journal, entryTimeStr))
Jason M. Billse1f26342018-07-18 12:12:00 -07002002 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002003 return 1;
Jason M. Billse1f26342018-07-18 12:12:00 -07002004 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002005
2006 // Fill in the log entry with the gathered data
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002007 bmcJournalLogEntryJson = {
Andrew Geisslercb92c032018-08-17 07:56:14 -07002008 {"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002009 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/" +
2010 bmcJournalLogEntryID},
Jason M. Billse1f26342018-07-18 12:12:00 -07002011 {"Name", "BMC Journal Entry"},
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002012 {"Id", bmcJournalLogEntryID},
Jason M. Billsa8fe54f2020-11-20 15:57:55 -08002013 {"Message", std::move(message)},
Jason M. Billse1f26342018-07-18 12:12:00 -07002014 {"EntryType", "Oem"},
Patrick Williams738c1e62021-02-22 17:14:25 -06002015 {"Severity", severity <= 2 ? "Critical"
2016 : severity <= 4 ? "Warning"
2017 : "OK"},
Ed Tanous086be232019-05-23 11:47:09 -07002018 {"OemRecordFormat", "BMC Journal Entry"},
Jason M. Billse1f26342018-07-18 12:12:00 -07002019 {"Created", std::move(entryTimeStr)}};
2020 return 0;
2021}
2022
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002023class BMCJournalLogEntryCollection : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002024{
2025 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002026 BMCJournalLogEntryCollection(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002027 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/")
Jason M. Billse1f26342018-07-18 12:12:00 -07002028 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002029 entityPrivileges = {
2030 {boost::beast::http::verb::get, {{"Login"}}},
2031 {boost::beast::http::verb::head, {{"Login"}}},
2032 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2033 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2034 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2035 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2036 }
2037
2038 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002039 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2040 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002041 const std::vector<std::string>&) override
Jason M. Billse1f26342018-07-18 12:12:00 -07002042 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002043
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002044 static constexpr const long maxEntriesPerPage = 1000;
Ed Tanous271584a2019-07-09 16:24:22 -07002045 uint64_t skip = 0;
2046 uint64_t top = maxEntriesPerPage; // Show max entries by default
zhanghch058d1b46d2021-04-01 11:18:24 +08002047 if (!getSkipParam(asyncResp, req, skip))
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002048 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002049 return;
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002050 }
zhanghch058d1b46d2021-04-01 11:18:24 +08002051 if (!getTopParam(asyncResp, req, top))
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. Billse1f26342018-07-18 12:12:00 -07002055 // Collections don't include the static data added by SubRoute because
2056 // it has a duplicate entry for members
2057 asyncResp->res.jsonValue["@odata.type"] =
2058 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002059 asyncResp->res.jsonValue["@odata.id"] =
2060 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002061 asyncResp->res.jsonValue["Name"] = "Open BMC Journal Entries";
2062 asyncResp->res.jsonValue["Description"] =
2063 "Collection of BMC Journal Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002064 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07002065 logEntryArray = nlohmann::json::array();
2066
2067 // Go through the journal and use the timestamp to create a unique ID
2068 // for each entry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002069 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07002070 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2071 if (ret < 0)
2072 {
2073 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07002074 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002075 return;
2076 }
2077 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2078 journalTmp, sd_journal_close);
2079 journalTmp = nullptr;
Ed Tanousb01bf292019-03-25 19:25:26 +00002080 uint64_t entryCount = 0;
Jason M. Billse85d6b12019-07-29 17:01:15 -07002081 // Reset the unique ID on the first entry
2082 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07002083 SD_JOURNAL_FOREACH(journal.get())
2084 {
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002085 entryCount++;
2086 // Handle paging using skip (number of entries to skip from the
2087 // start) and top (number of entries to display)
2088 if (entryCount <= skip || entryCount > skip + top)
2089 {
2090 continue;
2091 }
2092
Jason M. Bills16428a12018-11-02 12:42:29 -07002093 std::string idStr;
Jason M. Billse85d6b12019-07-29 17:01:15 -07002094 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
Jason M. Billse1f26342018-07-18 12:12:00 -07002095 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002096 continue;
2097 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002098
Jason M. Billse85d6b12019-07-29 17:01:15 -07002099 if (firstEntry)
2100 {
2101 firstEntry = false;
2102 }
2103
Jason M. Billse1f26342018-07-18 12:12:00 -07002104 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002105 nlohmann::json& bmcJournalLogEntry = logEntryArray.back();
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002106 if (fillBMCJournalLogEntryJson(idStr, journal.get(),
2107 bmcJournalLogEntry) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07002108 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002109 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002110 return;
2111 }
2112 }
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002113 asyncResp->res.jsonValue["Members@odata.count"] = entryCount;
2114 if (skip + top < entryCount)
2115 {
2116 asyncResp->res.jsonValue["Members@odata.nextLink"] =
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002117 "/redfish/v1/Managers/bmc/LogServices/Journal/Entries?$skip=" +
Jason M. Bills193ad2f2018-09-26 15:08:52 -07002118 std::to_string(skip + top);
2119 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002120 }
2121};
2122
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002123class BMCJournalLogEntry : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002124{
2125 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002126 BMCJournalLogEntry(App& app) :
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002127 Node(app, "/redfish/v1/Managers/bmc/LogServices/Journal/Entries/<str>/",
Jason M. Billse1f26342018-07-18 12:12:00 -07002128 std::string())
2129 {
2130 entityPrivileges = {
2131 {boost::beast::http::verb::get, {{"Login"}}},
2132 {boost::beast::http::verb::head, {{"Login"}}},
2133 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2134 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2135 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2136 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2137 }
2138
2139 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002140 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2141 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002142 const std::vector<std::string>& params) override
Jason M. Billse1f26342018-07-18 12:12:00 -07002143 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002144
Jason M. Billse1f26342018-07-18 12:12:00 -07002145 if (params.size() != 1)
2146 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002147 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002148 return;
2149 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002150 const std::string& entryID = params[0];
Jason M. Billse1f26342018-07-18 12:12:00 -07002151 // Convert the unique ID back to a timestamp to find the entry
Jason M. Billse1f26342018-07-18 12:12:00 -07002152 uint64_t ts = 0;
Ed Tanous271584a2019-07-09 16:24:22 -07002153 uint64_t index = 0;
zhanghch058d1b46d2021-04-01 11:18:24 +08002154 if (!getTimestampFromID(asyncResp, entryID, ts, index))
Jason M. Billse1f26342018-07-18 12:12:00 -07002155 {
Jason M. Bills16428a12018-11-02 12:42:29 -07002156 return;
Jason M. Billse1f26342018-07-18 12:12:00 -07002157 }
2158
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002159 sd_journal* journalTmp = nullptr;
Jason M. Billse1f26342018-07-18 12:12:00 -07002160 int ret = sd_journal_open(&journalTmp, SD_JOURNAL_LOCAL_ONLY);
2161 if (ret < 0)
2162 {
2163 BMCWEB_LOG_ERROR << "failed to open journal: " << strerror(-ret);
Jason M. Billsf12894f2018-10-09 12:45:45 -07002164 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002165 return;
2166 }
2167 std::unique_ptr<sd_journal, decltype(&sd_journal_close)> journal(
2168 journalTmp, sd_journal_close);
2169 journalTmp = nullptr;
2170 // Go to the timestamp in the log and move to the entry at the index
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002171 // tracking the unique ID
2172 std::string idStr;
2173 bool firstEntry = true;
Jason M. Billse1f26342018-07-18 12:12:00 -07002174 ret = sd_journal_seek_realtime_usec(journal.get(), ts);
Manojkiran Eda2056b6d2020-05-28 08:57:36 +05302175 if (ret < 0)
2176 {
2177 BMCWEB_LOG_ERROR << "failed to seek to an entry in journal"
2178 << strerror(-ret);
2179 messages::internalError(asyncResp->res);
2180 return;
2181 }
Ed Tanous271584a2019-07-09 16:24:22 -07002182 for (uint64_t i = 0; i <= index; i++)
Jason M. Billse1f26342018-07-18 12:12:00 -07002183 {
2184 sd_journal_next(journal.get());
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002185 if (!getUniqueEntryID(journal.get(), idStr, firstEntry))
2186 {
2187 messages::internalError(asyncResp->res);
2188 return;
2189 }
2190 if (firstEntry)
2191 {
2192 firstEntry = false;
2193 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002194 }
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002195 // Confirm that the entry ID matches what was requested
Jason M. Billsaf07e3f2019-08-01 14:41:39 -07002196 if (idStr != entryID)
Jason M. Billsc4bf6372018-11-05 13:48:27 -08002197 {
2198 messages::resourceMissingAtURI(asyncResp->res, entryID);
2199 return;
2200 }
2201
2202 if (fillBMCJournalLogEntryJson(entryID, journal.get(),
2203 asyncResp->res.jsonValue) != 0)
Jason M. Billse1f26342018-07-18 12:12:00 -07002204 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002205 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002206 return;
2207 }
2208 }
2209};
2210
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002211class BMCDumpService : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002212{
2213 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002214 BMCDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002215 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002216 {
2217 entityPrivileges = {
2218 {boost::beast::http::verb::get, {{"Login"}}},
2219 {boost::beast::http::verb::head, {{"Login"}}},
2220 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2221 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2222 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2223 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2224 }
2225
2226 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002227 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2228 const crow::Request&, const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002229 {
raviteja-bc9bb6862020-02-03 11:53:32 -06002230
2231 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002232 "/redfish/v1/Managers/bmc/LogServices/Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002233 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002234 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002235 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2236 asyncResp->res.jsonValue["Description"] = "BMC Dump LogService";
2237 asyncResp->res.jsonValue["Id"] = "Dump";
raviteja-bc9bb6862020-02-03 11:53:32 -06002238 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
raviteja-bc9bb6862020-02-03 11:53:32 -06002239 asyncResp->res.jsonValue["Entries"] = {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002240 {"@odata.id", "/redfish/v1/Managers/bmc/LogServices/Dump/Entries"}};
2241 asyncResp->res.jsonValue["Actions"] = {
2242 {"#LogService.ClearLog",
2243 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2244 "Actions/LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002245 {"#LogService.CollectDiagnosticData",
2246 {{"target", "/redfish/v1/Managers/bmc/LogServices/Dump/"
2247 "Actions/LogService.CollectDiagnosticData"}}}};
raviteja-bc9bb6862020-02-03 11:53:32 -06002248 }
2249};
2250
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002251class BMCDumpEntryCollection : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002252{
2253 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002254 BMCDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002255 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/")
raviteja-bc9bb6862020-02-03 11:53:32 -06002256 {
2257 entityPrivileges = {
2258 {boost::beast::http::verb::get, {{"Login"}}},
2259 {boost::beast::http::verb::head, {{"Login"}}},
2260 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2261 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2262 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2263 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2264 }
2265
2266 private:
2267 /**
2268 * Functions triggers appropriate requests on DBus
2269 */
zhanghch058d1b46d2021-04-01 11:18:24 +08002270 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2271 const crow::Request&, const std::vector<std::string>&) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002272 {
raviteja-bc9bb6862020-02-03 11:53:32 -06002273
2274 asyncResp->res.jsonValue["@odata.type"] =
2275 "#LogEntryCollection.LogEntryCollection";
2276 asyncResp->res.jsonValue["@odata.id"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002277 "/redfish/v1/Managers/bmc/LogServices/Dump/Entries";
2278 asyncResp->res.jsonValue["Name"] = "BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002279 asyncResp->res.jsonValue["Description"] =
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002280 "Collection of BMC Dump Entries";
raviteja-bc9bb6862020-02-03 11:53:32 -06002281
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002282 getDumpEntryCollection(asyncResp, "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002283 }
2284};
2285
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002286class BMCDumpEntry : public Node
raviteja-bc9bb6862020-02-03 11:53:32 -06002287{
2288 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002289 BMCDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002290 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/Entries/<str>/",
raviteja-bc9bb6862020-02-03 11:53:32 -06002291 std::string())
2292 {
2293 entityPrivileges = {
2294 {boost::beast::http::verb::get, {{"Login"}}},
2295 {boost::beast::http::verb::head, {{"Login"}}},
2296 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2297 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2298 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2299 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2300 }
2301
2302 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002303 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2304 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002305 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002306 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002307
raviteja-bc9bb6862020-02-03 11:53:32 -06002308 if (params.size() != 1)
2309 {
2310 messages::internalError(asyncResp->res);
2311 return;
2312 }
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002313 getDumpEntryById(asyncResp, params[0], "BMC");
raviteja-bc9bb6862020-02-03 11:53:32 -06002314 }
2315
zhanghch058d1b46d2021-04-01 11:18:24 +08002316 void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2317 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002318 const std::vector<std::string>& params) override
raviteja-bc9bb6862020-02-03 11:53:32 -06002319 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002320
raviteja-bc9bb6862020-02-03 11:53:32 -06002321 if (params.size() != 1)
2322 {
2323 messages::internalError(asyncResp->res);
2324 return;
2325 }
Stanley Chu98782562020-11-04 16:10:24 +08002326 deleteDumpEntry(asyncResp, params[0], "bmc");
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002327 }
2328};
raviteja-bc9bb6862020-02-03 11:53:32 -06002329
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002330class BMCDumpCreate : public Node
2331{
2332 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002333 BMCDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002334 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002335 "Actions/"
2336 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002337 {
2338 entityPrivileges = {
2339 {boost::beast::http::verb::get, {{"Login"}}},
2340 {boost::beast::http::verb::head, {{"Login"}}},
2341 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2342 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2343 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2344 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2345 }
2346
2347 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002348 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2349 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002350 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002351 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002352 createDump(asyncResp, req, "BMC");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002353 }
2354};
2355
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002356class BMCDumpClear : public Node
2357{
2358 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002359 BMCDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002360 Node(app, "/redfish/v1/Managers/bmc/LogServices/Dump/"
2361 "Actions/"
2362 "LogService.ClearLog/")
2363 {
2364 entityPrivileges = {
2365 {boost::beast::http::verb::get, {{"Login"}}},
2366 {boost::beast::http::verb::head, {{"Login"}}},
2367 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2368 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2369 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2370 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2371 }
2372
2373 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002374 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2375 const crow::Request&, const std::vector<std::string>&) override
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002376 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002377 clearDump(asyncResp, "BMC");
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002378 }
2379};
2380
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002381class SystemDumpService : public Node
2382{
2383 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002384 SystemDumpService(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002385 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/")
2386 {
2387 entityPrivileges = {
2388 {boost::beast::http::verb::get, {{"Login"}}},
2389 {boost::beast::http::verb::head, {{"Login"}}},
2390 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2391 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2392 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2393 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2394 }
raviteja-bc9bb6862020-02-03 11:53:32 -06002395
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002396 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002397 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2398 const crow::Request&, const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002399 {
raviteja-bc9bb6862020-02-03 11:53:32 -06002400
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002401 asyncResp->res.jsonValue["@odata.id"] =
2402 "/redfish/v1/Systems/system/LogServices/Dump";
2403 asyncResp->res.jsonValue["@odata.type"] =
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002404 "#LogService.v1_2_0.LogService";
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002405 asyncResp->res.jsonValue["Name"] = "Dump LogService";
2406 asyncResp->res.jsonValue["Description"] = "System Dump LogService";
2407 asyncResp->res.jsonValue["Id"] = "Dump";
2408 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2409 asyncResp->res.jsonValue["Entries"] = {
2410 {"@odata.id",
2411 "/redfish/v1/Systems/system/LogServices/Dump/Entries"}};
2412 asyncResp->res.jsonValue["Actions"] = {
2413 {"#LogService.ClearLog",
2414 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2415 "LogService.ClearLog"}}},
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002416 {"#LogService.CollectDiagnosticData",
2417 {{"target", "/redfish/v1/Systems/system/LogServices/Dump/Actions/"
2418 "LogService.CollectDiagnosticData"}}}};
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002419 }
2420};
2421
2422class SystemDumpEntryCollection : public Node
2423{
2424 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002425 SystemDumpEntryCollection(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002426 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/")
2427 {
2428 entityPrivileges = {
2429 {boost::beast::http::verb::get, {{"Login"}}},
2430 {boost::beast::http::verb::head, {{"Login"}}},
2431 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2432 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2433 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2434 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2435 }
2436
2437 private:
2438 /**
2439 * Functions triggers appropriate requests on DBus
2440 */
zhanghch058d1b46d2021-04-01 11:18:24 +08002441 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2442 const crow::Request&, const std::vector<std::string>&) override
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002443 {
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002444
2445 asyncResp->res.jsonValue["@odata.type"] =
2446 "#LogEntryCollection.LogEntryCollection";
2447 asyncResp->res.jsonValue["@odata.id"] =
2448 "/redfish/v1/Systems/system/LogServices/Dump/Entries";
2449 asyncResp->res.jsonValue["Name"] = "System Dump Entries";
2450 asyncResp->res.jsonValue["Description"] =
2451 "Collection of System Dump Entries";
2452
2453 getDumpEntryCollection(asyncResp, "System");
2454 }
2455};
2456
2457class SystemDumpEntry : public Node
2458{
2459 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002460 SystemDumpEntry(App& app) :
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002461 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/Entries/<str>/",
2462 std::string())
2463 {
2464 entityPrivileges = {
2465 {boost::beast::http::verb::get, {{"Login"}}},
2466 {boost::beast::http::verb::head, {{"Login"}}},
2467 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2468 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2469 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2470 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2471 }
2472
2473 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002474 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2475 const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002476 const std::vector<std::string>& params) override
2477 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002478
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002479 if (params.size() != 1)
2480 {
2481 messages::internalError(asyncResp->res);
2482 return;
2483 }
2484 getDumpEntryById(asyncResp, params[0], "System");
2485 }
2486
zhanghch058d1b46d2021-04-01 11:18:24 +08002487 void doDelete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2488 const crow::Request&,
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002489 const std::vector<std::string>& params) override
2490 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002491
Asmitha Karunanithi5cb1dd22020-05-07 04:35:02 -05002492 if (params.size() != 1)
2493 {
2494 messages::internalError(asyncResp->res);
2495 return;
2496 }
Stanley Chu98782562020-11-04 16:10:24 +08002497 deleteDumpEntry(asyncResp, params[0], "system");
raviteja-bc9bb6862020-02-03 11:53:32 -06002498 }
2499};
2500
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002501class SystemDumpCreate : public Node
2502{
2503 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002504 SystemDumpCreate(App& app) :
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002505 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
Asmitha Karunanithid337bb72020-09-21 10:34:02 -05002506 "Actions/"
2507 "LogService.CollectDiagnosticData/")
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002508 {
2509 entityPrivileges = {
2510 {boost::beast::http::verb::get, {{"Login"}}},
2511 {boost::beast::http::verb::head, {{"Login"}}},
2512 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2513 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2514 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2515 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2516 }
2517
2518 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002519 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2520 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002521 const std::vector<std::string>&) override
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002522 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002523 createDump(asyncResp, req, "System");
Asmitha Karunanithia43be802020-05-07 05:05:36 -05002524 }
2525};
2526
raviteja-b013487e2020-03-03 03:20:48 -06002527class SystemDumpClear : public Node
2528{
2529 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002530 SystemDumpClear(App& app) :
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002531 Node(app, "/redfish/v1/Systems/system/LogServices/Dump/"
raviteja-b013487e2020-03-03 03:20:48 -06002532 "Actions/"
2533 "LogService.ClearLog/")
2534 {
2535 entityPrivileges = {
2536 {boost::beast::http::verb::get, {{"Login"}}},
2537 {boost::beast::http::verb::head, {{"Login"}}},
Asmitha Karunanithi80319af2020-05-07 05:30:21 -05002538 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2539 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2540 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
raviteja-b013487e2020-03-03 03:20:48 -06002541 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2542 }
2543
2544 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002545 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2546 const crow::Request&, const std::vector<std::string>&) override
raviteja-b013487e2020-03-03 03:20:48 -06002547 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002548 clearDump(asyncResp, "System");
raviteja-b013487e2020-03-03 03:20:48 -06002549 }
2550};
2551
Jason M. Bills424c4172019-03-21 13:50:33 -07002552class CrashdumpService : public Node
Jason M. Billse1f26342018-07-18 12:12:00 -07002553{
2554 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002555 CrashdumpService(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002556 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002557 {
AppaRao Puli39460282020-04-07 17:03:04 +05302558 // Note: Deviated from redfish privilege registry for GET & HEAD
2559 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002560 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302561 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2562 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002563 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2564 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2565 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2566 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002567 }
2568
2569 private:
2570 /**
2571 * Functions triggers appropriate requests on DBus
2572 */
zhanghch058d1b46d2021-04-01 11:18:24 +08002573 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2574 const crow::Request&, const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002575 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002576
Ed Tanous1da66f72018-07-27 16:13:37 -07002577 // Copy over the static data to include the entries added by SubRoute
Ed Tanous0f74e642018-11-12 15:17:05 -08002578 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002579 "/redfish/v1/Systems/system/LogServices/Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002580 asyncResp->res.jsonValue["@odata.type"] =
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002581 "#LogService.v1_2_0.LogService";
Gunnar Mills4f50ae42020-02-06 15:29:57 -06002582 asyncResp->res.jsonValue["Name"] = "Open BMC Oem Crashdump Service";
2583 asyncResp->res.jsonValue["Description"] = "Oem Crashdump Service";
2584 asyncResp->res.jsonValue["Id"] = "Oem Crashdump";
Jason M. Billse1f26342018-07-18 12:12:00 -07002585 asyncResp->res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
2586 asyncResp->res.jsonValue["MaxNumberOfRecords"] = 3;
Jason M. Billscd50aa42019-02-12 17:09:02 -08002587 asyncResp->res.jsonValue["Entries"] = {
2588 {"@odata.id",
Jason M. Bills424c4172019-03-21 13:50:33 -07002589 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries"}};
Jason M. Billse1f26342018-07-18 12:12:00 -07002590 asyncResp->res.jsonValue["Actions"] = {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002591 {"#LogService.ClearLog",
2592 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2593 "Actions/LogService.ClearLog"}}},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002594 {"#LogService.CollectDiagnosticData",
2595 {{"target", "/redfish/v1/Systems/system/LogServices/Crashdump/"
2596 "Actions/LogService.CollectDiagnosticData"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002597 }
2598};
2599
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002600class CrashdumpClear : public Node
2601{
2602 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002603 CrashdumpClear(App& app) :
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002604 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2605 "LogService.ClearLog/")
2606 {
AppaRao Puli39460282020-04-07 17:03:04 +05302607 // Note: Deviated from redfish privilege registry for GET & HEAD
2608 // method for security reasons.
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002609 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302610 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2611 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002612 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2613 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2614 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2615 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2616 }
2617
2618 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002619 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2620 const crow::Request&, const std::vector<std::string>&) override
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002621 {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002622
2623 crow::connections::systemBus->async_method_call(
2624 [asyncResp](const boost::system::error_code ec,
Ed Tanouscb13a392020-07-25 19:02:03 +00002625 const std::string&) {
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002626 if (ec)
2627 {
2628 messages::internalError(asyncResp->res);
2629 return;
2630 }
2631 messages::success(asyncResp->res);
2632 },
2633 crashdumpObject, crashdumpPath, deleteAllInterface, "DeleteAll");
2634 }
2635};
2636
zhanghch058d1b46d2021-04-01 11:18:24 +08002637static void
2638 logCrashdumpEntry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2639 const std::string& logID, nlohmann::json& logEntryJson)
Jason M. Billse855dd22019-10-08 11:37:48 -07002640{
Johnathan Mantey043a0532020-03-10 17:15:28 -07002641 auto getStoredLogCallback =
2642 [asyncResp, logID, &logEntryJson](
2643 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002644 const std::vector<std::pair<std::string, VariantType>>& params) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002645 if (ec)
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002646 {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002647 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2648 if (ec.value() ==
2649 boost::system::linux_error::bad_request_descriptor)
2650 {
2651 messages::resourceNotFound(asyncResp->res, "LogEntry",
2652 logID);
2653 }
2654 else
2655 {
2656 messages::internalError(asyncResp->res);
2657 }
2658 return;
Jason M. Bills1ddcf012019-11-26 14:59:21 -08002659 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002660
Johnathan Mantey043a0532020-03-10 17:15:28 -07002661 std::string timestamp{};
2662 std::string filename{};
2663 std::string logfile{};
Ed Tanous2c70f802020-09-28 14:29:23 -07002664 parseCrashdumpParameters(params, filename, timestamp, logfile);
Johnathan Mantey043a0532020-03-10 17:15:28 -07002665
2666 if (filename.empty() || timestamp.empty())
2667 {
2668 messages::resourceMissingAtURI(asyncResp->res, logID);
2669 return;
2670 }
2671
2672 std::string crashdumpURI =
2673 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/" +
2674 logID + "/" + filename;
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002675 logEntryJson = {{"@odata.type", "#LogEntry.v1_7_0.LogEntry"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002676 {"@odata.id", "/redfish/v1/Systems/system/"
2677 "LogServices/Crashdump/Entries/" +
2678 logID},
2679 {"Name", "CPU Crashdump"},
2680 {"Id", logID},
2681 {"EntryType", "Oem"},
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002682 {"AdditionalDataURI", std::move(crashdumpURI)},
2683 {"DiagnosticDataType", "OEM"},
2684 {"OEMDiagnosticDataType", "PECICrashdump"},
Johnathan Mantey043a0532020-03-10 17:15:28 -07002685 {"Created", std::move(timestamp)}};
2686 };
Jason M. Billse855dd22019-10-08 11:37:48 -07002687 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002688 std::move(getStoredLogCallback), crashdumpObject,
2689 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002690 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Jason M. Billse855dd22019-10-08 11:37:48 -07002691}
2692
Jason M. Bills424c4172019-03-21 13:50:33 -07002693class CrashdumpEntryCollection : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002694{
2695 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002696 CrashdumpEntryCollection(App& app) :
Jason M. Bills424c4172019-03-21 13:50:33 -07002697 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002698 {
AppaRao Puli39460282020-04-07 17:03:04 +05302699 // Note: Deviated from redfish privilege registry for GET & HEAD
2700 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002701 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302702 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2703 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002704 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2705 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2706 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2707 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002708 }
2709
2710 private:
2711 /**
2712 * Functions triggers appropriate requests on DBus
2713 */
zhanghch058d1b46d2021-04-01 11:18:24 +08002714 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2715 const crow::Request&, const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002716 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002717
Ed Tanous1da66f72018-07-27 16:13:37 -07002718 // Collections don't include the static data added by SubRoute because
2719 // it has a duplicate entry for members
Jason M. Billse1f26342018-07-18 12:12:00 -07002720 auto getLogEntriesCallback = [asyncResp](
2721 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002722 const std::vector<std::string>& resp) {
Jason M. Billse1f26342018-07-18 12:12:00 -07002723 if (ec)
2724 {
2725 if (ec.value() !=
2726 boost::system::errc::no_such_file_or_directory)
Ed Tanous1da66f72018-07-27 16:13:37 -07002727 {
Jason M. Billse1f26342018-07-18 12:12:00 -07002728 BMCWEB_LOG_DEBUG << "failed to get entries ec: "
2729 << ec.message();
Jason M. Billsf12894f2018-10-09 12:45:45 -07002730 messages::internalError(asyncResp->res);
Jason M. Billse1f26342018-07-18 12:12:00 -07002731 return;
Ed Tanous1da66f72018-07-27 16:13:37 -07002732 }
Jason M. Billse1f26342018-07-18 12:12:00 -07002733 }
2734 asyncResp->res.jsonValue["@odata.type"] =
2735 "#LogEntryCollection.LogEntryCollection";
Ed Tanous0f74e642018-11-12 15:17:05 -08002736 asyncResp->res.jsonValue["@odata.id"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002737 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries";
Jason M. Bills424c4172019-03-21 13:50:33 -07002738 asyncResp->res.jsonValue["Name"] = "Open BMC Crashdump Entries";
Jason M. Billse1f26342018-07-18 12:12:00 -07002739 asyncResp->res.jsonValue["Description"] =
Jason M. Bills424c4172019-03-21 13:50:33 -07002740 "Collection of Crashdump Entries";
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002741 nlohmann::json& logEntryArray = asyncResp->res.jsonValue["Members"];
Jason M. Billse1f26342018-07-18 12:12:00 -07002742 logEntryArray = nlohmann::json::array();
Jason M. Billse855dd22019-10-08 11:37:48 -07002743 std::vector<std::string> logIDs;
2744 // Get the list of log entries and build up an empty array big
2745 // enough to hold them
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002746 for (const std::string& objpath : resp)
Jason M. Billse1f26342018-07-18 12:12:00 -07002747 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002748 // Get the log ID
Ed Tanousf23b7292020-10-15 09:41:17 -07002749 std::size_t lastPos = objpath.rfind('/');
Jason M. Billse855dd22019-10-08 11:37:48 -07002750 if (lastPos == std::string::npos)
Jason M. Billse1f26342018-07-18 12:12:00 -07002751 {
Jason M. Billse855dd22019-10-08 11:37:48 -07002752 continue;
Jason M. Billse1f26342018-07-18 12:12:00 -07002753 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002754 logIDs.emplace_back(objpath.substr(lastPos + 1));
2755
2756 // Add a space for the log entry to the array
2757 logEntryArray.push_back({});
2758 }
2759 // Now go through and set up async calls to fill in the entries
2760 size_t index = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002761 for (const std::string& logID : logIDs)
Jason M. Billse855dd22019-10-08 11:37:48 -07002762 {
2763 // Add the log entry to the array
2764 logCrashdumpEntry(asyncResp, logID, logEntryArray[index++]);
Jason M. Billse1f26342018-07-18 12:12:00 -07002765 }
2766 asyncResp->res.jsonValue["Members@odata.count"] =
2767 logEntryArray.size();
2768 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002769 crow::connections::systemBus->async_method_call(
2770 std::move(getLogEntriesCallback),
2771 "xyz.openbmc_project.ObjectMapper",
2772 "/xyz/openbmc_project/object_mapper",
2773 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002774 std::array<const char*, 1>{crashdumpInterface});
Ed Tanous1da66f72018-07-27 16:13:37 -07002775 }
2776};
2777
Jason M. Bills424c4172019-03-21 13:50:33 -07002778class CrashdumpEntry : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002779{
2780 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002781 CrashdumpEntry(App& app) :
Jason M. Billsd53dd412019-02-12 17:16:22 -08002782 Node(app,
Jason M. Bills424c4172019-03-21 13:50:33 -07002783 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/",
Ed Tanous1da66f72018-07-27 16:13:37 -07002784 std::string())
2785 {
AppaRao Puli39460282020-04-07 17:03:04 +05302786 // Note: Deviated from redfish privilege registry for GET & HEAD
2787 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002788 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302789 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2790 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse1f26342018-07-18 12:12:00 -07002791 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2792 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2793 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2794 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002795 }
2796
2797 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002798 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2799 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002800 const std::vector<std::string>& params) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002801 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002802
Ed Tanous1da66f72018-07-27 16:13:37 -07002803 if (params.size() != 1)
2804 {
Jason M. Billsf12894f2018-10-09 12:45:45 -07002805 messages::internalError(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002806 return;
2807 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002808 const std::string& logID = params[0];
Jason M. Billse855dd22019-10-08 11:37:48 -07002809 logCrashdumpEntry(asyncResp, logID, asyncResp->res.jsonValue);
2810 }
2811};
2812
2813class CrashdumpFile : public Node
2814{
2815 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07002816 CrashdumpFile(App& app) :
Jason M. Billse855dd22019-10-08 11:37:48 -07002817 Node(app,
2818 "/redfish/v1/Systems/system/LogServices/Crashdump/Entries/<str>/"
2819 "<str>/",
2820 std::string(), std::string())
2821 {
AppaRao Puli39460282020-04-07 17:03:04 +05302822 // Note: Deviated from redfish privilege registry for GET & HEAD
2823 // method for security reasons.
Jason M. Billse855dd22019-10-08 11:37:48 -07002824 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302825 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2826 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
Jason M. Billse855dd22019-10-08 11:37:48 -07002827 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
2828 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
2829 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
2830 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
2831 }
2832
2833 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002834 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2835 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002836 const std::vector<std::string>& params) override
Jason M. Billse855dd22019-10-08 11:37:48 -07002837 {
zhanghch058d1b46d2021-04-01 11:18:24 +08002838
Jason M. Billse855dd22019-10-08 11:37:48 -07002839 if (params.size() != 2)
2840 {
2841 messages::internalError(asyncResp->res);
2842 return;
2843 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002844 const std::string& logID = params[0];
2845 const std::string& fileName = params[1];
Jason M. Billse855dd22019-10-08 11:37:48 -07002846
Johnathan Mantey043a0532020-03-10 17:15:28 -07002847 auto getStoredLogCallback =
2848 [asyncResp, logID, fileName](
2849 const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002850 const std::vector<std::pair<std::string, VariantType>>& resp) {
Johnathan Mantey043a0532020-03-10 17:15:28 -07002851 if (ec)
2852 {
2853 BMCWEB_LOG_DEBUG << "failed to get log ec: "
2854 << ec.message();
2855 messages::internalError(asyncResp->res);
2856 return;
2857 }
Jason M. Billse855dd22019-10-08 11:37:48 -07002858
Johnathan Mantey043a0532020-03-10 17:15:28 -07002859 std::string dbusFilename{};
2860 std::string dbusTimestamp{};
2861 std::string dbusFilepath{};
Jason M. Billse855dd22019-10-08 11:37:48 -07002862
Ed Tanous2c70f802020-09-28 14:29:23 -07002863 parseCrashdumpParameters(resp, dbusFilename, dbusTimestamp,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002864 dbusFilepath);
2865
2866 if (dbusFilename.empty() || dbusTimestamp.empty() ||
2867 dbusFilepath.empty())
2868 {
2869 messages::resourceMissingAtURI(asyncResp->res, fileName);
2870 return;
2871 }
2872
2873 // Verify the file name parameter is correct
2874 if (fileName != dbusFilename)
2875 {
2876 messages::resourceMissingAtURI(asyncResp->res, fileName);
2877 return;
2878 }
2879
2880 if (!std::filesystem::exists(dbusFilepath))
2881 {
2882 messages::resourceMissingAtURI(asyncResp->res, fileName);
2883 return;
2884 }
2885 std::ifstream ifs(dbusFilepath, std::ios::in |
2886 std::ios::binary |
2887 std::ios::ate);
2888 std::ifstream::pos_type fileSize = ifs.tellg();
2889 if (fileSize < 0)
2890 {
2891 messages::generalError(asyncResp->res);
2892 return;
2893 }
2894 ifs.seekg(0, std::ios::beg);
2895
2896 auto crashData = std::make_unique<char[]>(
2897 static_cast<unsigned int>(fileSize));
2898
2899 ifs.read(crashData.get(), static_cast<int>(fileSize));
2900
2901 // The cast to std::string is intentional in order to use the
2902 // assign() that applies move mechanics
2903 asyncResp->res.body().assign(
2904 static_cast<std::string>(crashData.get()));
2905
2906 // Configure this to be a file download when accessed from
2907 // a browser
2908 asyncResp->res.addHeader("Content-Disposition", "attachment");
2909 };
Ed Tanous1da66f72018-07-27 16:13:37 -07002910 crow::connections::systemBus->async_method_call(
Jason M. Bills5b61b5e2019-10-16 10:59:02 -07002911 std::move(getStoredLogCallback), crashdumpObject,
2912 crashdumpPath + std::string("/") + logID,
Johnathan Mantey043a0532020-03-10 17:15:28 -07002913 "org.freedesktop.DBus.Properties", "GetAll", crashdumpInterface);
Ed Tanous1da66f72018-07-27 16:13:37 -07002914 }
2915};
2916
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002917class CrashdumpCollect : public Node
Ed Tanous1da66f72018-07-27 16:13:37 -07002918{
2919 public:
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002920 CrashdumpCollect(App& app) :
2921 Node(app, "/redfish/v1/Systems/system/LogServices/Crashdump/Actions/"
2922 "LogService.CollectDiagnosticData/")
Ed Tanous1da66f72018-07-27 16:13:37 -07002923 {
AppaRao Puli39460282020-04-07 17:03:04 +05302924 // Note: Deviated from redfish privilege registry for GET & HEAD
2925 // method for security reasons.
Ed Tanous1da66f72018-07-27 16:13:37 -07002926 entityPrivileges = {
AppaRao Puli39460282020-04-07 17:03:04 +05302927 {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2928 {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
2929 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2930 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2931 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2932 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
Ed Tanous1da66f72018-07-27 16:13:37 -07002933 }
2934
2935 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08002936 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2937 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00002938 const std::vector<std::string>&) override
Ed Tanous1da66f72018-07-27 16:13:37 -07002939 {
Ed Tanous1da66f72018-07-27 16:13:37 -07002940
Jason M. Bills8e6c0992021-03-11 16:26:53 -08002941 std::string diagnosticDataType;
2942 std::string oemDiagnosticDataType;
2943 if (!redfish::json_util::readJson(
2944 req, asyncResp->res, "DiagnosticDataType", diagnosticDataType,
2945 "OEMDiagnosticDataType", oemDiagnosticDataType))
2946 {
2947 return;
2948 }
2949
2950 if (diagnosticDataType != "OEM")
2951 {
2952 BMCWEB_LOG_ERROR
2953 << "Only OEM DiagnosticDataType supported for Crashdump";
2954 messages::actionParameterValueFormatError(
2955 asyncResp->res, diagnosticDataType, "DiagnosticDataType",
2956 "CollectDiagnosticData");
2957 return;
2958 }
2959
2960 auto collectCrashdumpCallback = [asyncResp, req](
2961 const boost::system::error_code ec,
2962 const std::string&) {
James Feist46229572020-02-19 15:11:58 -08002963 if (ec)
2964 {
2965 if (ec.value() == boost::system::errc::operation_not_supported)
Ed Tanous1da66f72018-07-27 16:13:37 -07002966 {
James Feist46229572020-02-19 15:11:58 -08002967 messages::resourceInStandby(asyncResp->res);
Ed Tanous1da66f72018-07-27 16:13:37 -07002968 }
James Feist46229572020-02-19 15:11:58 -08002969 else if (ec.value() ==
2970 boost::system::errc::device_or_resource_busy)
2971 {
2972 messages::serviceTemporarilyUnavailable(asyncResp->res,
2973 "60");
2974 }
2975 else
2976 {
2977 messages::internalError(asyncResp->res);
2978 }
2979 return;
2980 }
2981 std::shared_ptr<task::TaskData> task = task::TaskData::createTask(
Gunnar Mills1214b7e2020-06-04 10:11:30 -05002982 [](boost::system::error_code err, sdbusplus::message::message&,
2983 const std::shared_ptr<task::TaskData>& taskData) {
James Feist66afe4f2020-02-24 13:09:58 -08002984 if (!err)
2985 {
James Feiste5d50062020-05-11 17:29:00 -07002986 taskData->messages.emplace_back(
2987 messages::taskCompletedOK(
2988 std::to_string(taskData->index)));
James Feist831d6b02020-03-12 16:31:30 -07002989 taskData->state = "Completed";
James Feist66afe4f2020-02-24 13:09:58 -08002990 }
James Feist32898ce2020-03-10 16:16:52 -07002991 return task::completed;
James Feist66afe4f2020-02-24 13:09:58 -08002992 },
James Feist46229572020-02-19 15:11:58 -08002993 "type='signal',interface='org.freedesktop.DBus.Properties',"
2994 "member='PropertiesChanged',arg0namespace='com.intel."
2995 "crashdump'");
2996 task->startTimer(std::chrono::minutes(5));
2997 task->populateResp(asyncResp->res);
James Feistfe306722020-03-12 16:32:08 -07002998 task->payload.emplace(req);
James Feist46229572020-02-19 15:11:58 -08002999 };
Ed Tanous1da66f72018-07-27 16:13:37 -07003000
Jason M. Bills8e6c0992021-03-11 16:26:53 -08003001 if (oemDiagnosticDataType == "OnDemand")
3002 {
3003 crow::connections::systemBus->async_method_call(
3004 std::move(collectCrashdumpCallback), crashdumpObject,
3005 crashdumpPath, crashdumpOnDemandInterface,
3006 "GenerateOnDemandLog");
3007 }
3008 else if (oemDiagnosticDataType == "Telemetry")
3009 {
3010 crow::connections::systemBus->async_method_call(
3011 std::move(collectCrashdumpCallback), crashdumpObject,
3012 crashdumpPath, crashdumpTelemetryInterface,
3013 "GenerateTelemetryLog");
3014 }
3015 else
3016 {
3017 BMCWEB_LOG_ERROR << "Unsupported OEMDiagnosticDataType: "
3018 << oemDiagnosticDataType;
3019 messages::actionParameterValueFormatError(
3020 asyncResp->res, oemDiagnosticDataType, "OEMDiagnosticDataType",
3021 "CollectDiagnosticData");
3022 return;
3023 }
Kenny L. Ku6eda7682020-06-19 09:48:36 -07003024 }
3025};
3026
Andrew Geisslercb92c032018-08-17 07:56:14 -07003027/**
3028 * DBusLogServiceActionsClear class supports POST method for ClearLog action.
3029 */
3030class DBusLogServiceActionsClear : public Node
3031{
3032 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003033 DBusLogServiceActionsClear(App& app) :
Andrew Geisslercb92c032018-08-17 07:56:14 -07003034 Node(app, "/redfish/v1/Systems/system/LogServices/EventLog/Actions/"
Gunnar Mills7af91512020-04-14 22:16:57 -05003035 "LogService.ClearLog/")
Andrew Geisslercb92c032018-08-17 07:56:14 -07003036 {
3037 entityPrivileges = {
3038 {boost::beast::http::verb::get, {{"Login"}}},
3039 {boost::beast::http::verb::head, {{"Login"}}},
3040 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3041 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3042 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3043 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3044 }
3045
3046 private:
3047 /**
3048 * Function handles POST method request.
3049 * The Clear Log actions does not require any parameter.The action deletes
3050 * all entries found in the Entries collection for this Log Service.
3051 */
zhanghch058d1b46d2021-04-01 11:18:24 +08003052 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3053 const crow::Request&, const std::vector<std::string>&) override
Andrew Geisslercb92c032018-08-17 07:56:14 -07003054 {
3055 BMCWEB_LOG_DEBUG << "Do delete all entries.";
3056
Andrew Geisslercb92c032018-08-17 07:56:14 -07003057 // Process response from Logging service.
Ed Tanous2c70f802020-09-28 14:29:23 -07003058 auto respHandler = [asyncResp](const boost::system::error_code ec) {
Andrew Geisslercb92c032018-08-17 07:56:14 -07003059 BMCWEB_LOG_DEBUG << "doClearLog resp_handler callback: Done";
3060 if (ec)
3061 {
3062 // TODO Handle for specific error code
3063 BMCWEB_LOG_ERROR << "doClearLog resp_handler got error " << ec;
3064 asyncResp->res.result(
3065 boost::beast::http::status::internal_server_error);
3066 return;
3067 }
3068
3069 asyncResp->res.result(boost::beast::http::status::no_content);
3070 };
3071
3072 // Make call to Logging service to request Clear Log
3073 crow::connections::systemBus->async_method_call(
Ed Tanous2c70f802020-09-28 14:29:23 -07003074 respHandler, "xyz.openbmc_project.Logging",
Andrew Geisslercb92c032018-08-17 07:56:14 -07003075 "/xyz/openbmc_project/logging",
3076 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3077 }
3078};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003079
3080/****************************************************
3081 * Redfish PostCode interfaces
3082 * using DBUS interface: getPostCodesTS
3083 ******************************************************/
3084class PostCodesLogService : public Node
3085{
3086 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003087 PostCodesLogService(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003088 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/")
3089 {
3090 entityPrivileges = {
3091 {boost::beast::http::verb::get, {{"Login"}}},
3092 {boost::beast::http::verb::head, {{"Login"}}},
3093 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3094 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3095 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3096 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3097 }
3098
3099 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08003100 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3101 const crow::Request&, const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003102 {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003103
3104 asyncResp->res.jsonValue = {
3105 {"@odata.id", "/redfish/v1/Systems/system/LogServices/PostCodes"},
3106 {"@odata.type", "#LogService.v1_1_0.LogService"},
ZhikuiRena3316fc2020-01-29 14:58:08 -08003107 {"Name", "POST Code Log Service"},
3108 {"Description", "POST Code Log Service"},
3109 {"Id", "BIOS POST Code Log"},
3110 {"OverWritePolicy", "WrapsWhenFull"},
3111 {"Entries",
3112 {{"@odata.id",
3113 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries"}}}};
3114 asyncResp->res.jsonValue["Actions"]["#LogService.ClearLog"] = {
3115 {"target", "/redfish/v1/Systems/system/LogServices/PostCodes/"
3116 "Actions/LogService.ClearLog"}};
3117 }
3118};
3119
3120class PostCodesClear : public Node
3121{
3122 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003123 PostCodesClear(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003124 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Actions/"
3125 "LogService.ClearLog/")
3126 {
3127 entityPrivileges = {
3128 {boost::beast::http::verb::get, {{"Login"}}},
3129 {boost::beast::http::verb::head, {{"Login"}}},
AppaRao Puli39460282020-04-07 17:03:04 +05303130 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
3131 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
3132 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
3133 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003134 }
3135
3136 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08003137 void doPost(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3138 const crow::Request&, const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003139 {
3140 BMCWEB_LOG_DEBUG << "Do delete all postcodes entries.";
3141
ZhikuiRena3316fc2020-01-29 14:58:08 -08003142 // Make call to post-code service to request clear all
3143 crow::connections::systemBus->async_method_call(
3144 [asyncResp](const boost::system::error_code ec) {
3145 if (ec)
3146 {
3147 // TODO Handle for specific error code
3148 BMCWEB_LOG_ERROR
3149 << "doClearPostCodes resp_handler got error " << ec;
3150 asyncResp->res.result(
3151 boost::beast::http::status::internal_server_error);
3152 messages::internalError(asyncResp->res);
3153 return;
3154 }
3155 },
Jonathan Doman15124762021-01-07 17:54:17 -08003156 "xyz.openbmc_project.State.Boot.PostCode0",
3157 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003158 "xyz.openbmc_project.Collection.DeleteAll", "DeleteAll");
3159 }
3160};
3161
3162static void fillPostCodeEntry(
zhanghch058d1b46d2021-04-01 11:18:24 +08003163 const std::shared_ptr<bmcweb::AsyncResp>& aResp,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303164 const boost::container::flat_map<
3165 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>& postcode,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003166 const uint16_t bootIndex, const uint64_t codeIndex = 0,
3167 const uint64_t skip = 0, const uint64_t top = 0)
3168{
3169 // Get the Message from the MessageRegistry
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003170 const message_registries::Message* message =
Manojkiran Eda4a0bf532021-04-21 22:46:14 +05303171 message_registries::getMessage("OpenBMC.0.2.BIOSPOSTCode");
ZhikuiRena3316fc2020-01-29 14:58:08 -08003172
3173 uint64_t currentCodeIndex = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003174 nlohmann::json& logEntryArray = aResp->res.jsonValue["Members"];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003175
3176 uint64_t firstCodeTimeUs = 0;
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303177 for (const std::pair<uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3178 code : postcode)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003179 {
3180 currentCodeIndex++;
3181 std::string postcodeEntryID =
3182 "B" + std::to_string(bootIndex) + "-" +
3183 std::to_string(currentCodeIndex); // 1 based index in EntryID string
3184
3185 uint64_t usecSinceEpoch = code.first;
3186 uint64_t usTimeOffset = 0;
3187
3188 if (1 == currentCodeIndex)
3189 { // already incremented
3190 firstCodeTimeUs = code.first;
3191 }
3192 else
3193 {
3194 usTimeOffset = code.first - firstCodeTimeUs;
3195 }
3196
3197 // skip if no specific codeIndex is specified and currentCodeIndex does
3198 // not fall between top and skip
3199 if ((codeIndex == 0) &&
3200 (currentCodeIndex <= skip || currentCodeIndex > top))
3201 {
3202 continue;
3203 }
3204
Gunnar Mills4e0453b2020-07-08 14:00:30 -05003205 // skip if a specific codeIndex is specified and does not match the
ZhikuiRena3316fc2020-01-29 14:58:08 -08003206 // currentIndex
3207 if ((codeIndex > 0) && (currentCodeIndex != codeIndex))
3208 {
3209 // This is done for simplicity. 1st entry is needed to calculate
3210 // time offset. To improve efficiency, one can get to the entry
3211 // directly (possibly with flatmap's nth method)
3212 continue;
3213 }
3214
3215 // currentCodeIndex is within top and skip or equal to specified code
3216 // index
3217
3218 // Get the Created time from the timestamp
3219 std::string entryTimeStr;
Asmitha Karunanithi9c620e22020-08-02 11:55:21 -05003220 entryTimeStr = crow::utility::getDateTime(
3221 static_cast<std::time_t>(usecSinceEpoch / 1000 / 1000));
ZhikuiRena3316fc2020-01-29 14:58:08 -08003222
3223 // assemble messageArgs: BootIndex, TimeOffset(100us), PostCode(hex)
3224 std::ostringstream hexCode;
3225 hexCode << "0x" << std::setfill('0') << std::setw(2) << std::hex
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303226 << std::get<0>(code.second);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003227 std::ostringstream timeOffsetStr;
3228 // Set Fixed -Point Notation
3229 timeOffsetStr << std::fixed;
3230 // Set precision to 4 digits
3231 timeOffsetStr << std::setprecision(4);
3232 // Add double to stream
3233 timeOffsetStr << static_cast<double>(usTimeOffset) / 1000 / 1000;
3234 std::vector<std::string> messageArgs = {
3235 std::to_string(bootIndex), timeOffsetStr.str(), hexCode.str()};
3236
3237 // Get MessageArgs template from message registry
3238 std::string msg;
3239 if (message != nullptr)
3240 {
3241 msg = message->message;
3242
3243 // fill in this post code value
3244 int i = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003245 for (const std::string& messageArg : messageArgs)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003246 {
3247 std::string argStr = "%" + std::to_string(++i);
3248 size_t argPos = msg.find(argStr);
3249 if (argPos != std::string::npos)
3250 {
3251 msg.replace(argPos, argStr.length(), messageArg);
3252 }
3253 }
3254 }
3255
Tim Leed4342a92020-04-27 11:47:58 +08003256 // Get Severity template from message registry
3257 std::string severity;
3258 if (message != nullptr)
3259 {
3260 severity = message->severity;
3261 }
3262
ZhikuiRena3316fc2020-01-29 14:58:08 -08003263 // add to AsyncResp
3264 logEntryArray.push_back({});
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003265 nlohmann::json& bmcLogEntry = logEntryArray.back();
Gunnar Mills743e9a12020-10-26 12:44:53 -05003266 bmcLogEntry = {{"@odata.type", "#LogEntry.v1_4_0.LogEntry"},
3267 {"@odata.id", "/redfish/v1/Systems/system/LogServices/"
3268 "PostCodes/Entries/" +
3269 postcodeEntryID},
3270 {"Name", "POST Code Log Entry"},
3271 {"Id", postcodeEntryID},
3272 {"Message", std::move(msg)},
Manojkiran Eda4a0bf532021-04-21 22:46:14 +05303273 {"MessageId", "OpenBMC.0.2.BIOSPOSTCode"},
Gunnar Mills743e9a12020-10-26 12:44:53 -05003274 {"MessageArgs", std::move(messageArgs)},
3275 {"EntryType", "Event"},
3276 {"Severity", std::move(severity)},
3277 {"Created", entryTimeStr}};
ZhikuiRena3316fc2020-01-29 14:58:08 -08003278 }
3279}
3280
zhanghch058d1b46d2021-04-01 11:18:24 +08003281static void getPostCodeForEntry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003282 const uint16_t bootIndex,
3283 const uint64_t codeIndex)
3284{
3285 crow::connections::systemBus->async_method_call(
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303286 [aResp, bootIndex,
3287 codeIndex](const boost::system::error_code ec,
3288 const boost::container::flat_map<
3289 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3290 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003291 if (ec)
3292 {
3293 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3294 messages::internalError(aResp->res);
3295 return;
3296 }
3297
3298 // skip the empty postcode boots
3299 if (postcode.empty())
3300 {
3301 return;
3302 }
3303
3304 fillPostCodeEntry(aResp, postcode, bootIndex, codeIndex);
3305
3306 aResp->res.jsonValue["Members@odata.count"] =
3307 aResp->res.jsonValue["Members"].size();
3308 },
Jonathan Doman15124762021-01-07 17:54:17 -08003309 "xyz.openbmc_project.State.Boot.PostCode0",
3310 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003311 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3312 bootIndex);
3313}
3314
zhanghch058d1b46d2021-04-01 11:18:24 +08003315static void getPostCodeForBoot(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
ZhikuiRena3316fc2020-01-29 14:58:08 -08003316 const uint16_t bootIndex,
3317 const uint16_t bootCount,
3318 const uint64_t entryCount, const uint64_t skip,
3319 const uint64_t top)
3320{
3321 crow::connections::systemBus->async_method_call(
3322 [aResp, bootIndex, bootCount, entryCount, skip,
3323 top](const boost::system::error_code ec,
Manojkiran Eda6c9a2792021-02-27 14:25:04 +05303324 const boost::container::flat_map<
3325 uint64_t, std::tuple<uint64_t, std::vector<uint8_t>>>&
3326 postcode) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003327 if (ec)
3328 {
3329 BMCWEB_LOG_DEBUG << "DBUS POST CODE PostCode response error";
3330 messages::internalError(aResp->res);
3331 return;
3332 }
3333
3334 uint64_t endCount = entryCount;
3335 if (!postcode.empty())
3336 {
3337 endCount = entryCount + postcode.size();
3338
3339 if ((skip < endCount) && ((top + skip) > entryCount))
3340 {
3341 uint64_t thisBootSkip =
3342 std::max(skip, entryCount) - entryCount;
3343 uint64_t thisBootTop =
3344 std::min(top + skip, endCount) - entryCount;
3345
3346 fillPostCodeEntry(aResp, postcode, bootIndex, 0,
3347 thisBootSkip, thisBootTop);
3348 }
3349 aResp->res.jsonValue["Members@odata.count"] = endCount;
3350 }
3351
3352 // continue to previous bootIndex
3353 if (bootIndex < bootCount)
3354 {
3355 getPostCodeForBoot(aResp, static_cast<uint16_t>(bootIndex + 1),
3356 bootCount, endCount, skip, top);
3357 }
3358 else
3359 {
3360 aResp->res.jsonValue["Members@odata.nextLink"] =
3361 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3362 "Entries?$skip=" +
3363 std::to_string(skip + top);
3364 }
3365 },
Jonathan Doman15124762021-01-07 17:54:17 -08003366 "xyz.openbmc_project.State.Boot.PostCode0",
3367 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003368 "xyz.openbmc_project.State.Boot.PostCode", "GetPostCodesWithTimeStamp",
3369 bootIndex);
3370}
3371
zhanghch058d1b46d2021-04-01 11:18:24 +08003372static void
3373 getCurrentBootNumber(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
3374 const uint64_t skip, const uint64_t top)
ZhikuiRena3316fc2020-01-29 14:58:08 -08003375{
3376 uint64_t entryCount = 0;
3377 crow::connections::systemBus->async_method_call(
3378 [aResp, entryCount, skip,
3379 top](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003380 const std::variant<uint16_t>& bootCount) {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003381 if (ec)
3382 {
3383 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
3384 messages::internalError(aResp->res);
3385 return;
3386 }
3387 auto pVal = std::get_if<uint16_t>(&bootCount);
3388 if (pVal)
3389 {
3390 getPostCodeForBoot(aResp, 1, *pVal, entryCount, skip, top);
3391 }
3392 else
3393 {
3394 BMCWEB_LOG_DEBUG << "Post code boot index failed.";
3395 }
3396 },
Jonathan Doman15124762021-01-07 17:54:17 -08003397 "xyz.openbmc_project.State.Boot.PostCode0",
3398 "/xyz/openbmc_project/State/Boot/PostCode0",
ZhikuiRena3316fc2020-01-29 14:58:08 -08003399 "org.freedesktop.DBus.Properties", "Get",
3400 "xyz.openbmc_project.State.Boot.PostCode", "CurrentBootCycleCount");
3401}
3402
3403class PostCodesEntryCollection : public Node
3404{
3405 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003406 PostCodesEntryCollection(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003407 Node(app, "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/")
3408 {
3409 entityPrivileges = {
3410 {boost::beast::http::verb::get, {{"Login"}}},
3411 {boost::beast::http::verb::head, {{"Login"}}},
3412 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3413 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3414 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3415 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3416 }
3417
3418 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08003419 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3420 const crow::Request& req,
Ed Tanouscb13a392020-07-25 19:02:03 +00003421 const std::vector<std::string>&) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003422 {
ZhikuiRena3316fc2020-01-29 14:58:08 -08003423
3424 asyncResp->res.jsonValue["@odata.type"] =
3425 "#LogEntryCollection.LogEntryCollection";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003426 asyncResp->res.jsonValue["@odata.id"] =
3427 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries";
3428 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3429 asyncResp->res.jsonValue["Description"] =
3430 "Collection of POST Code Log Entries";
3431 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3432 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3433
3434 uint64_t skip = 0;
3435 uint64_t top = maxEntriesPerPage; // Show max entries by default
zhanghch058d1b46d2021-04-01 11:18:24 +08003436 if (!getSkipParam(asyncResp, req, skip))
ZhikuiRena3316fc2020-01-29 14:58:08 -08003437 {
3438 return;
3439 }
zhanghch058d1b46d2021-04-01 11:18:24 +08003440 if (!getTopParam(asyncResp, req, top))
ZhikuiRena3316fc2020-01-29 14:58:08 -08003441 {
3442 return;
3443 }
3444 getCurrentBootNumber(asyncResp, skip, top);
3445 }
3446};
3447
3448class PostCodesEntry : public Node
3449{
3450 public:
Ed Tanous52cc1122020-07-18 13:51:21 -07003451 PostCodesEntry(App& app) :
ZhikuiRena3316fc2020-01-29 14:58:08 -08003452 Node(app,
3453 "/redfish/v1/Systems/system/LogServices/PostCodes/Entries/<str>/",
3454 std::string())
3455 {
3456 entityPrivileges = {
3457 {boost::beast::http::verb::get, {{"Login"}}},
3458 {boost::beast::http::verb::head, {{"Login"}}},
3459 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
3460 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
3461 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
3462 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
3463 }
3464
3465 private:
zhanghch058d1b46d2021-04-01 11:18:24 +08003466 void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3467 const crow::Request&,
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003468 const std::vector<std::string>& params) override
ZhikuiRena3316fc2020-01-29 14:58:08 -08003469 {
zhanghch058d1b46d2021-04-01 11:18:24 +08003470
ZhikuiRena3316fc2020-01-29 14:58:08 -08003471 if (params.size() != 1)
3472 {
3473 messages::internalError(asyncResp->res);
3474 return;
3475 }
3476
Gunnar Mills1214b7e2020-06-04 10:11:30 -05003477 const std::string& targetID = params[0];
ZhikuiRena3316fc2020-01-29 14:58:08 -08003478
3479 size_t bootPos = targetID.find('B');
3480 if (bootPos == std::string::npos)
3481 {
3482 // Requested ID was not found
3483 messages::resourceMissingAtURI(asyncResp->res, targetID);
3484 return;
3485 }
3486 std::string_view bootIndexStr(targetID);
3487 bootIndexStr.remove_prefix(bootPos + 1);
3488 uint16_t bootIndex = 0;
3489 uint64_t codeIndex = 0;
3490 size_t dashPos = bootIndexStr.find('-');
3491
3492 if (dashPos == std::string::npos)
3493 {
3494 return;
3495 }
3496 std::string_view codeIndexStr(bootIndexStr);
3497 bootIndexStr.remove_suffix(dashPos);
3498 codeIndexStr.remove_prefix(dashPos + 1);
3499
3500 bootIndex = static_cast<uint16_t>(
Ed Tanous23a21a12020-07-25 04:45:05 +00003501 strtoul(std::string(bootIndexStr).c_str(), nullptr, 0));
3502 codeIndex = strtoul(std::string(codeIndexStr).c_str(), nullptr, 0);
ZhikuiRena3316fc2020-01-29 14:58:08 -08003503 if (bootIndex == 0 || codeIndex == 0)
3504 {
3505 BMCWEB_LOG_DEBUG << "Get Post Code invalid entry string "
3506 << params[0];
3507 }
3508
3509 asyncResp->res.jsonValue["@odata.type"] = "#LogEntry.v1_4_0.LogEntry";
ZhikuiRena3316fc2020-01-29 14:58:08 -08003510 asyncResp->res.jsonValue["@odata.id"] =
3511 "/redfish/v1/Systems/system/LogServices/PostCodes/"
3512 "Entries";
3513 asyncResp->res.jsonValue["Name"] = "BIOS POST Code Log Entries";
3514 asyncResp->res.jsonValue["Description"] =
3515 "Collection of POST Code Log Entries";
3516 asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
3517 asyncResp->res.jsonValue["Members@odata.count"] = 0;
3518
3519 getPostCodeForEntry(asyncResp, bootIndex, codeIndex);
3520 }
3521};
3522
Ed Tanous1da66f72018-07-27 16:13:37 -07003523} // namespace redfish