xref: /openbmc/bmcweb/features/redfish/lib/log_services.hpp (revision 4ed77cd5cfcef505b2e33cd571d92d3dc6caac3a)
11da66f75SEd Tanous /*
21da66f75SEd Tanous // Copyright (c) 2018 Intel Corporation
31da66f75SEd Tanous //
41da66f75SEd Tanous // Licensed under the Apache License, Version 2.0 (the "License");
51da66f75SEd Tanous // you may not use this file except in compliance with the License.
61da66f75SEd Tanous // You may obtain a copy of the License at
71da66f75SEd Tanous //
81da66f75SEd Tanous //      http://www.apache.org/licenses/LICENSE-2.0
91da66f75SEd Tanous //
101da66f75SEd Tanous // Unless required by applicable law or agreed to in writing, software
111da66f75SEd Tanous // distributed under the License is distributed on an "AS IS" BASIS,
121da66f75SEd Tanous // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131da66f75SEd Tanous // See the License for the specific language governing permissions and
141da66f75SEd Tanous // limitations under the License.
151da66f75SEd Tanous */
161da66f75SEd Tanous #pragma once
171da66f75SEd Tanous 
181da66f75SEd Tanous #include "node.hpp"
191da66f75SEd Tanous 
201da66f75SEd Tanous #include <boost/container/flat_map.hpp>
211da66f75SEd Tanous #include <experimental/filesystem>
221da66f75SEd Tanous 
231da66f75SEd Tanous namespace redfish
241da66f75SEd Tanous {
251da66f75SEd Tanous 
26*4ed77cd5SEd Tanous constexpr char const *cpuLogObject = "com.intel.CpuDebugLog";
27*4ed77cd5SEd Tanous constexpr char const *cpuLogPath = "/com/intel/CpuDebugLog";
28*4ed77cd5SEd Tanous constexpr char const *cpuLogImmediatePath = "/com/intel/CpuDebugLog/Immediate";
29*4ed77cd5SEd Tanous constexpr char const *cpuLogInterface = "com.intel.CpuDebugLog";
30*4ed77cd5SEd Tanous constexpr char const *cpuLogImmediateInterface =
311da66f75SEd Tanous     "com.intel.CpuDebugLog.Immediate";
32*4ed77cd5SEd Tanous constexpr char const *cpuLogRawPeciInterface =
331da66f75SEd Tanous     "com.intel.CpuDebugLog.SendRawPeci";
341da66f75SEd Tanous 
351da66f75SEd Tanous namespace fs = std::experimental::filesystem;
361da66f75SEd Tanous 
371da66f75SEd Tanous class LogServiceCollection : public Node
381da66f75SEd Tanous {
391da66f75SEd Tanous   public:
401da66f75SEd Tanous     template <typename CrowApp>
411da66f75SEd Tanous     LogServiceCollection(CrowApp &app) :
42*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/")
431da66f75SEd Tanous     {
441da66f75SEd Tanous         // Collections use static ID for SubRoute to add to its parent, but only
451da66f75SEd Tanous         // load dynamic data so the duplicate static members don't get displayed
46*4ed77cd5SEd Tanous         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
471da66f75SEd Tanous         entityPrivileges = {
481da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
491da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
501da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
511da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
521da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
531da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
541da66f75SEd Tanous     }
551da66f75SEd Tanous 
561da66f75SEd Tanous   private:
571da66f75SEd Tanous     /**
581da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
591da66f75SEd Tanous      */
601da66f75SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
611da66f75SEd Tanous                const std::vector<std::string> &params) override
621da66f75SEd Tanous     {
631da66f75SEd Tanous         // Collections don't include the static data added by SubRoute because
641da66f75SEd Tanous         // it has a duplicate entry for members
651da66f75SEd Tanous         res.jsonValue["@odata.type"] =
661da66f75SEd Tanous             "#LogServiceCollection.LogServiceCollection";
671da66f75SEd Tanous         res.jsonValue["@odata.context"] =
681da66f75SEd Tanous             "/redfish/v1/"
691da66f75SEd Tanous             "$metadata#LogServiceCollection.LogServiceCollection";
70*4ed77cd5SEd Tanous         res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices";
711da66f75SEd Tanous         res.jsonValue["Name"] = "Open BMC Log Services Collection";
721da66f75SEd Tanous         res.jsonValue["Description"] =
731da66f75SEd Tanous             "Collection of LogServices for this Manager";
741da66f75SEd Tanous         nlohmann::json &logserviceArray = res.jsonValue["Members"];
751da66f75SEd Tanous         logserviceArray = nlohmann::json::array();
761da66f75SEd Tanous #ifdef BMCWEB_ENABLE_REDFISH_CPU_LOG
771da66f75SEd Tanous         logserviceArray.push_back(
78*4ed77cd5SEd Tanous             {{"@odata.id", "/redfish/v1/Managers/bmc/LogServices/CpuLog"}});
791da66f75SEd Tanous #endif
801da66f75SEd Tanous         res.jsonValue["Members@odata.count"] = logserviceArray.size();
811da66f75SEd Tanous         res.end();
821da66f75SEd Tanous     }
831da66f75SEd Tanous };
841da66f75SEd Tanous 
851da66f75SEd Tanous class CpuLogService : public Node
861da66f75SEd Tanous {
871da66f75SEd Tanous   public:
881da66f75SEd Tanous     template <typename CrowApp>
891da66f75SEd Tanous     CpuLogService(CrowApp &app) :
90*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog")
911da66f75SEd Tanous     {
921da66f75SEd Tanous         // Set the id for SubRoute
93*4ed77cd5SEd Tanous         Node::json["@odata.id"] = "/redfish/v1/Managers/bmc/LogServices/CpuLog";
941da66f75SEd Tanous         entityPrivileges = {
951da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
961da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
971da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
981da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
991da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1001da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1011da66f75SEd Tanous     }
1021da66f75SEd Tanous 
1031da66f75SEd Tanous   private:
1041da66f75SEd Tanous     /**
1051da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
1061da66f75SEd Tanous      */
1071da66f75SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1081da66f75SEd Tanous                const std::vector<std::string> &params) override
1091da66f75SEd Tanous     {
1101da66f75SEd Tanous         // Copy over the static data to include the entries added by SubRoute
1111da66f75SEd Tanous         res.jsonValue = Node::json;
1121da66f75SEd Tanous         res.jsonValue["@odata.type"] = "#LogService.v1_1_0.LogService";
1131da66f75SEd Tanous         res.jsonValue["@odata.context"] = "/redfish/v1/"
1141da66f75SEd Tanous                                           "$metadata#LogService.LogService";
1151da66f75SEd Tanous         res.jsonValue["Name"] = "Open BMC CPU Log Service";
1161da66f75SEd Tanous         res.jsonValue["Description"] = "CPU Log Service";
1171da66f75SEd Tanous         res.jsonValue["Id"] = "CPU Log";
1181da66f75SEd Tanous         res.jsonValue["OverWritePolicy"] = "WrapsWhenFull";
1191da66f75SEd Tanous         res.jsonValue["MaxNumberOfRecords"] = 3;
1201da66f75SEd Tanous         res.jsonValue["Actions"] = {
1211da66f75SEd Tanous             {"Oem",
1221da66f75SEd Tanous              {{"#CpuLog.Immediate",
1231da66f75SEd Tanous                {{"target",
124*4ed77cd5SEd Tanous                  "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
1251da66f75SEd Tanous                  "CpuLog.Immediate"}}}}}};
1261da66f75SEd Tanous 
1271da66f75SEd Tanous #ifdef BMCWEB_ENABLE_REDFISH_RAW_PECI
1281da66f75SEd Tanous         res.jsonValue["Actions"]["Oem"].push_back(
1291da66f75SEd Tanous             {"#CpuLog.SendRawPeci",
1301da66f75SEd Tanous              {{"target",
131*4ed77cd5SEd Tanous                "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
1321da66f75SEd Tanous                "CpuLog.SendRawPeci"}}});
1331da66f75SEd Tanous #endif
1341da66f75SEd Tanous         res.end();
1351da66f75SEd Tanous     }
1361da66f75SEd Tanous };
1371da66f75SEd Tanous 
1381da66f75SEd Tanous class CpuLogEntryCollection : public Node
1391da66f75SEd Tanous {
1401da66f75SEd Tanous   public:
1411da66f75SEd Tanous     template <typename CrowApp>
1421da66f75SEd Tanous     CpuLogEntryCollection(CrowApp &app) :
143*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries")
1441da66f75SEd Tanous     {
1451da66f75SEd Tanous         // Collections use static ID for SubRoute to add to its parent, but only
1461da66f75SEd Tanous         // load dynamic data so the duplicate static members don't get displayed
1471da66f75SEd Tanous         Node::json["@odata.id"] =
148*4ed77cd5SEd Tanous             "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries";
1491da66f75SEd Tanous         entityPrivileges = {
1501da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
1511da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
1521da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1531da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1541da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1551da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1561da66f75SEd Tanous     }
1571da66f75SEd Tanous 
1581da66f75SEd Tanous   private:
1591da66f75SEd Tanous     /**
1601da66f75SEd Tanous      * Functions triggers appropriate requests on DBus
1611da66f75SEd Tanous      */
1621da66f75SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
1631da66f75SEd Tanous                const std::vector<std::string> &params) override
1641da66f75SEd Tanous     {
1651da66f75SEd Tanous         // Collections don't include the static data added by SubRoute because
1661da66f75SEd Tanous         // it has a duplicate entry for members
1671da66f75SEd Tanous         auto getLogEntriesCallback =
1681da66f75SEd Tanous             [&res](const boost::system::error_code ec,
1691da66f75SEd Tanous                    const std::vector<std::string> &resp) {
1701da66f75SEd Tanous                 if (ec)
1711da66f75SEd Tanous                 {
1721da66f75SEd Tanous                     if (ec.value() !=
1731da66f75SEd Tanous                         boost::system::errc::no_such_file_or_directory)
1741da66f75SEd Tanous                     {
1751da66f75SEd Tanous                         BMCWEB_LOG_DEBUG << "failed to get entries ec: "
1761da66f75SEd Tanous                                          << ec.message();
1771da66f75SEd Tanous                         res.result(
1781da66f75SEd Tanous                             boost::beast::http::status::internal_server_error);
1791da66f75SEd Tanous                         res.end();
1801da66f75SEd Tanous                         return;
1811da66f75SEd Tanous                     }
1821da66f75SEd Tanous                 }
1831da66f75SEd Tanous                 res.jsonValue["@odata.type"] =
1841da66f75SEd Tanous                     "#LogEntryCollection.LogEntryCollection";
1851da66f75SEd Tanous                 res.jsonValue["@odata.context"] =
1861da66f75SEd Tanous                     "/redfish/v1/"
1871da66f75SEd Tanous                     "$metadata#LogEntryCollection.LogEntryCollection";
1881da66f75SEd Tanous                 res.jsonValue["Name"] = "Open BMC CPU Log Entries";
1891da66f75SEd Tanous                 res.jsonValue["Description"] = "Collection of CPU Log Entries";
190*4ed77cd5SEd Tanous                 nlohmann::json &logentryArray = res.jsonValue["Members"];
191*4ed77cd5SEd Tanous                 logentryArray = nlohmann::json::array();
1921da66f75SEd Tanous                 for (const std::string &objpath : resp)
1931da66f75SEd Tanous                 {
1941da66f75SEd Tanous                     // Don't list the immediate log
195*4ed77cd5SEd Tanous                     if (objpath.compare(cpuLogImmediatePath) == 0)
1961da66f75SEd Tanous                     {
1971da66f75SEd Tanous                         continue;
1981da66f75SEd Tanous                     }
199*4ed77cd5SEd Tanous                     std::size_t lastPos = objpath.rfind("/");
200*4ed77cd5SEd Tanous                     if (lastPos != std::string::npos)
2011da66f75SEd Tanous                     {
202*4ed77cd5SEd Tanous                         logentryArray.push_back(
203*4ed77cd5SEd Tanous                             {{"@odata.id", "/redfish/v1/Managers/bmc/"
2041da66f75SEd Tanous                                            "LogServices/CpuLog/Entries/" +
205*4ed77cd5SEd Tanous                                                objpath.substr(lastPos + 1)}});
2061da66f75SEd Tanous                     }
2071da66f75SEd Tanous                 }
208*4ed77cd5SEd Tanous                 res.jsonValue["Members@odata.count"] = logentryArray.size();
2091da66f75SEd Tanous                 res.end();
2101da66f75SEd Tanous             };
2111da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
2121da66f75SEd Tanous             std::move(getLogEntriesCallback),
2131da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper",
2141da66f75SEd Tanous             "/xyz/openbmc_project/object_mapper",
2151da66f75SEd Tanous             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "", 0,
216*4ed77cd5SEd Tanous             std::array<const char *, 1>{cpuLogInterface});
2171da66f75SEd Tanous     }
2181da66f75SEd Tanous };
2191da66f75SEd Tanous 
2201da66f75SEd Tanous std::string getLogCreatedTime(const nlohmann::json &cpuLog)
2211da66f75SEd Tanous {
2221da66f75SEd Tanous     nlohmann::json::const_iterator metaIt = cpuLog.find("metadata");
2231da66f75SEd Tanous     if (metaIt != cpuLog.end())
2241da66f75SEd Tanous     {
2251da66f75SEd Tanous         nlohmann::json::const_iterator tsIt = metaIt->find("timestamp");
2261da66f75SEd Tanous         if (tsIt != metaIt->end())
2271da66f75SEd Tanous         {
2281da66f75SEd Tanous             const std::string *logTime = tsIt->get_ptr<const std::string *>();
2291da66f75SEd Tanous             if (logTime != nullptr)
2301da66f75SEd Tanous             {
2311da66f75SEd Tanous                 return *logTime;
2321da66f75SEd Tanous             }
2331da66f75SEd Tanous         }
2341da66f75SEd Tanous     }
2351da66f75SEd Tanous     BMCWEB_LOG_DEBUG << "failed to find log timestamp";
2361da66f75SEd Tanous 
2371da66f75SEd Tanous     return std::string();
2381da66f75SEd Tanous }
2391da66f75SEd Tanous 
2401da66f75SEd Tanous class CpuLogEntry : public Node
2411da66f75SEd Tanous {
2421da66f75SEd Tanous   public:
2431da66f75SEd Tanous     CpuLogEntry(CrowApp &app) :
244*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/<str>/",
2451da66f75SEd Tanous              std::string())
2461da66f75SEd Tanous     {
2471da66f75SEd Tanous         entityPrivileges = {
2481da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
2491da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
2501da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2511da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2521da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2531da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2541da66f75SEd Tanous     }
2551da66f75SEd Tanous 
2561da66f75SEd Tanous   private:
2571da66f75SEd Tanous     void doGet(crow::Response &res, const crow::Request &req,
2581da66f75SEd Tanous                const std::vector<std::string> &params) override
2591da66f75SEd Tanous     {
2601da66f75SEd Tanous         if (params.size() != 1)
2611da66f75SEd Tanous         {
2621da66f75SEd Tanous             res.result(boost::beast::http::status::internal_server_error);
2631da66f75SEd Tanous             res.end();
2641da66f75SEd Tanous             return;
2651da66f75SEd Tanous         }
266*4ed77cd5SEd Tanous         const uint8_t logId = std::atoi(params[0].c_str());
2671da66f75SEd Tanous         auto getStoredLogCallback = [&res,
268*4ed77cd5SEd Tanous                                      logId](const boost::system::error_code ec,
2691da66f75SEd Tanous                                             const sdbusplus::message::variant<
2701da66f75SEd Tanous                                                 std::string> &resp) {
2711da66f75SEd Tanous             if (ec)
2721da66f75SEd Tanous             {
2731da66f75SEd Tanous                 BMCWEB_LOG_DEBUG << "failed to get log ec: " << ec.message();
2741da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
2751da66f75SEd Tanous                 res.end();
2761da66f75SEd Tanous                 return;
2771da66f75SEd Tanous             }
2781da66f75SEd Tanous             const std::string *log = mapbox::getPtr<const std::string>(resp);
2791da66f75SEd Tanous             if (log == nullptr)
2801da66f75SEd Tanous             {
2811da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
2821da66f75SEd Tanous                 res.end();
2831da66f75SEd Tanous                 return;
2841da66f75SEd Tanous             }
2851da66f75SEd Tanous             nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
2861da66f75SEd Tanous             if (j.is_discarded())
2871da66f75SEd Tanous             {
2881da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
2891da66f75SEd Tanous                 res.end();
2901da66f75SEd Tanous                 return;
2911da66f75SEd Tanous             }
2921da66f75SEd Tanous             std::string t = getLogCreatedTime(j);
2931da66f75SEd Tanous             res.jsonValue = {
2941da66f75SEd Tanous                 {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
2951da66f75SEd Tanous                 {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
2961da66f75SEd Tanous                 {"@odata.id",
297*4ed77cd5SEd Tanous                  "/redfish/v1/Managers/bmc/LogServices/CpuLog/Entries/" +
298*4ed77cd5SEd Tanous                      std::to_string(logId)},
2991da66f75SEd Tanous                 {"Name", "CPU Debug Log"},
300*4ed77cd5SEd Tanous                 {"Id", logId},
3011da66f75SEd Tanous                 {"EntryType", "Oem"},
3021da66f75SEd Tanous                 {"OemRecordFormat", "Intel CPU Log"},
3031da66f75SEd Tanous                 {"Oem", {{"Intel", std::move(j)}}},
3041da66f75SEd Tanous                 {"Created", std::move(t)}};
3051da66f75SEd Tanous             res.end();
3061da66f75SEd Tanous         };
3071da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
308*4ed77cd5SEd Tanous             std::move(getStoredLogCallback), cpuLogObject,
309*4ed77cd5SEd Tanous             cpuLogPath + std::string("/") + std::to_string(logId),
310*4ed77cd5SEd Tanous             "org.freedesktop.DBus.Properties", "Get", cpuLogInterface, "Log");
3111da66f75SEd Tanous     }
3121da66f75SEd Tanous };
3131da66f75SEd Tanous 
3141da66f75SEd Tanous class ImmediateCpuLog : public Node
3151da66f75SEd Tanous {
3161da66f75SEd Tanous   public:
3171da66f75SEd Tanous     ImmediateCpuLog(CrowApp &app) :
318*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
3191da66f75SEd Tanous                   "CpuLog.Immediate")
3201da66f75SEd Tanous     {
3211da66f75SEd Tanous         entityPrivileges = {
3221da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
3231da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
3241da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
3251da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
3261da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
3271da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
3281da66f75SEd Tanous     }
3291da66f75SEd Tanous 
3301da66f75SEd Tanous   private:
3311da66f75SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
3321da66f75SEd Tanous                 const std::vector<std::string> &params) override
3331da66f75SEd Tanous     {
3341da66f75SEd Tanous         static std::unique_ptr<sdbusplus::bus::match::match>
3351da66f75SEd Tanous             immediateLogMatcher;
3361da66f75SEd Tanous 
3371da66f75SEd Tanous         // Only allow one Immediate Log request at a time
3381da66f75SEd Tanous         if (immediateLogMatcher != nullptr)
3391da66f75SEd Tanous         {
3401da66f75SEd Tanous             res.addHeader("Retry-After", "30");
3411da66f75SEd Tanous             res.result(boost::beast::http::status::service_unavailable);
3421da66f75SEd Tanous             messages::addMessageToJson(
3431da66f75SEd Tanous                 res.jsonValue, messages::serviceTemporarilyUnavailable("30"),
3441da66f75SEd Tanous                 "/CpuLog.Immediate");
3451da66f75SEd Tanous             res.end();
3461da66f75SEd Tanous             return;
3471da66f75SEd Tanous         }
3481da66f75SEd Tanous         // Make this static so it survives outside this method
3491da66f75SEd Tanous         static boost::asio::deadline_timer timeout(*req.ioService);
3501da66f75SEd Tanous 
3511da66f75SEd Tanous         timeout.expires_from_now(boost::posix_time::seconds(30));
3521da66f75SEd Tanous         timeout.async_wait([&res](const boost::system::error_code &ec) {
3531da66f75SEd Tanous             immediateLogMatcher = nullptr;
3541da66f75SEd Tanous             if (ec)
3551da66f75SEd Tanous             {
3561da66f75SEd Tanous                 // operation_aborted is expected if timer is canceled before
3571da66f75SEd Tanous                 // completion.
3581da66f75SEd Tanous                 if (ec != boost::asio::error::operation_aborted)
3591da66f75SEd Tanous                 {
3601da66f75SEd Tanous                     BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
3611da66f75SEd Tanous                 }
3621da66f75SEd Tanous                 return;
3631da66f75SEd Tanous             }
3641da66f75SEd Tanous             BMCWEB_LOG_ERROR << "Timed out waiting for immediate log";
3651da66f75SEd Tanous 
3661da66f75SEd Tanous             res.result(boost::beast::http::status::internal_server_error);
3671da66f75SEd Tanous             res.end();
3681da66f75SEd Tanous         });
3691da66f75SEd Tanous 
3701da66f75SEd Tanous         auto immediateLogMatcherCallback = [&res](
3711da66f75SEd Tanous                                                sdbusplus::message::message &m) {
3721da66f75SEd Tanous             BMCWEB_LOG_DEBUG << "Immediate log available match fired";
3731da66f75SEd Tanous             boost::system::error_code ec;
3741da66f75SEd Tanous             timeout.cancel(ec);
3751da66f75SEd Tanous             if (ec)
3761da66f75SEd Tanous             {
3771da66f75SEd Tanous                 BMCWEB_LOG_ERROR << "error canceling timer " << ec;
3781da66f75SEd Tanous             }
379*4ed77cd5SEd Tanous             sdbusplus::message::object_path objPath;
3801da66f75SEd Tanous             boost::container::flat_map<
3811da66f75SEd Tanous                 std::string,
3821da66f75SEd Tanous                 boost::container::flat_map<
3831da66f75SEd Tanous                     std::string, sdbusplus::message::variant<std::string>>>
384*4ed77cd5SEd Tanous                 interfacesAdded;
385*4ed77cd5SEd Tanous             m.read(objPath, interfacesAdded);
3861da66f75SEd Tanous             const std::string *log = mapbox::getPtr<const std::string>(
387*4ed77cd5SEd Tanous                 interfacesAdded[cpuLogInterface]["Log"]);
3881da66f75SEd Tanous             if (log == nullptr)
3891da66f75SEd Tanous             {
3901da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
3911da66f75SEd Tanous                 res.end();
3921da66f75SEd Tanous                 // Careful with immediateLogMatcher.  It is a unique_ptr to the
3931da66f75SEd Tanous                 // match object inside which this lambda is executing.  Once it
3941da66f75SEd Tanous                 // is set to nullptr, the match object will be destroyed and the
3951da66f75SEd Tanous                 // lambda will lose its context, including res, so it needs to
3961da66f75SEd Tanous                 // be the last thing done.
3971da66f75SEd Tanous                 immediateLogMatcher = nullptr;
3981da66f75SEd Tanous                 return;
3991da66f75SEd Tanous             }
4001da66f75SEd Tanous             nlohmann::json j = nlohmann::json::parse(*log, nullptr, false);
4011da66f75SEd Tanous             if (j.is_discarded())
4021da66f75SEd Tanous             {
4031da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
4041da66f75SEd Tanous                 res.end();
4051da66f75SEd Tanous                 // Careful with immediateLogMatcher.  It is a unique_ptr to the
4061da66f75SEd Tanous                 // match object inside which this lambda is executing.  Once it
4071da66f75SEd Tanous                 // is set to nullptr, the match object will be destroyed and the
4081da66f75SEd Tanous                 // lambda will lose its context, including res, so it needs to
4091da66f75SEd Tanous                 // be the last thing done.
4101da66f75SEd Tanous                 immediateLogMatcher = nullptr;
4111da66f75SEd Tanous                 return;
4121da66f75SEd Tanous             }
4131da66f75SEd Tanous             std::string t = getLogCreatedTime(j);
4141da66f75SEd Tanous             res.jsonValue = {
4151da66f75SEd Tanous                 {"@odata.type", "#LogEntry.v1_3_0.LogEntry"},
4161da66f75SEd Tanous                 {"@odata.context", "/redfish/v1/$metadata#LogEntry.LogEntry"},
4171da66f75SEd Tanous                 {"Name", "CPU Debug Log"},
4181da66f75SEd Tanous                 {"EntryType", "Oem"},
4191da66f75SEd Tanous                 {"OemRecordFormat", "Intel CPU Log"},
4201da66f75SEd Tanous                 {"Oem", {{"Intel", std::move(j)}}},
4211da66f75SEd Tanous                 {"Created", std::move(t)}};
4221da66f75SEd Tanous             res.end();
4231da66f75SEd Tanous             // Careful with immediateLogMatcher.  It is a unique_ptr to the
4241da66f75SEd Tanous             // match object inside which this lambda is executing.  Once it is
4251da66f75SEd Tanous             // set to nullptr, the match object will be destroyed and the lambda
4261da66f75SEd Tanous             // will lose its context, including res, so it needs to be the last
4271da66f75SEd Tanous             // thing done.
4281da66f75SEd Tanous             immediateLogMatcher = nullptr;
4291da66f75SEd Tanous         };
4301da66f75SEd Tanous         immediateLogMatcher = std::make_unique<sdbusplus::bus::match::match>(
4311da66f75SEd Tanous             *crow::connections::systemBus,
4321da66f75SEd Tanous             sdbusplus::bus::match::rules::interfacesAdded() +
433*4ed77cd5SEd Tanous                 sdbusplus::bus::match::rules::argNpath(0, cpuLogImmediatePath),
4341da66f75SEd Tanous             std::move(immediateLogMatcherCallback));
4351da66f75SEd Tanous 
4361da66f75SEd Tanous         auto generateImmediateLogCallback =
4371da66f75SEd Tanous             [&res](const boost::system::error_code ec,
4381da66f75SEd Tanous                    const std::string &resp) {
4391da66f75SEd Tanous                 if (ec)
4401da66f75SEd Tanous                 {
4411da66f75SEd Tanous                     if (ec.value() ==
4421da66f75SEd Tanous                         boost::system::errc::operation_not_supported)
4431da66f75SEd Tanous                     {
4441da66f75SEd Tanous                         messages::addMessageToJson(
4451da66f75SEd Tanous                             res.jsonValue, messages::resourceInStandby(),
4461da66f75SEd Tanous                             "/CpuLog.Immediate");
4471da66f75SEd Tanous                         res.result(
4481da66f75SEd Tanous                             boost::beast::http::status::service_unavailable);
4491da66f75SEd Tanous                     }
4501da66f75SEd Tanous                     else
4511da66f75SEd Tanous                     {
4521da66f75SEd Tanous                         res.result(
4531da66f75SEd Tanous                             boost::beast::http::status::internal_server_error);
4541da66f75SEd Tanous                     }
4551da66f75SEd Tanous                     res.end();
4561da66f75SEd Tanous                     boost::system::error_code timeoutec;
4571da66f75SEd Tanous                     timeout.cancel(timeoutec);
4581da66f75SEd Tanous                     if (timeoutec)
4591da66f75SEd Tanous                     {
4601da66f75SEd Tanous                         BMCWEB_LOG_ERROR << "error canceling timer "
4611da66f75SEd Tanous                                          << timeoutec;
4621da66f75SEd Tanous                     }
4631da66f75SEd Tanous                     immediateLogMatcher = nullptr;
4641da66f75SEd Tanous                     return;
4651da66f75SEd Tanous                 }
4661da66f75SEd Tanous             };
4671da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
468*4ed77cd5SEd Tanous             std::move(generateImmediateLogCallback), cpuLogObject, cpuLogPath,
469*4ed77cd5SEd Tanous             cpuLogImmediateInterface, "GenerateImmediateLog");
4701da66f75SEd Tanous     }
4711da66f75SEd Tanous };
4721da66f75SEd Tanous 
4731da66f75SEd Tanous class SendRawPeci : public Node
4741da66f75SEd Tanous {
4751da66f75SEd Tanous   public:
4761da66f75SEd Tanous     SendRawPeci(CrowApp &app) :
477*4ed77cd5SEd Tanous         Node(app, "/redfish/v1/Managers/bmc/LogServices/CpuLog/Actions/Oem/"
4781da66f75SEd Tanous                   "CpuLog.SendRawPeci")
4791da66f75SEd Tanous     {
4801da66f75SEd Tanous         entityPrivileges = {
4811da66f75SEd Tanous             {boost::beast::http::verb::get, {{"ConfigureComponents"}}},
4821da66f75SEd Tanous             {boost::beast::http::verb::head, {{"ConfigureComponents"}}},
4831da66f75SEd Tanous             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
4841da66f75SEd Tanous             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
4851da66f75SEd Tanous             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
4861da66f75SEd Tanous             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
4871da66f75SEd Tanous     }
4881da66f75SEd Tanous 
4891da66f75SEd Tanous   private:
4901da66f75SEd Tanous     void doPost(crow::Response &res, const crow::Request &req,
4911da66f75SEd Tanous                 const std::vector<std::string> &params) override
4921da66f75SEd Tanous     {
4931da66f75SEd Tanous         // Get the Raw PECI command from the request
4941da66f75SEd Tanous         nlohmann::json rawPeciCmd;
4951da66f75SEd Tanous         if (!json_util::processJsonFromRequest(res, req, rawPeciCmd))
4961da66f75SEd Tanous         {
4971da66f75SEd Tanous             return;
4981da66f75SEd Tanous         }
4991da66f75SEd Tanous         // Get the Client Address from the request
5001da66f75SEd Tanous         nlohmann::json::const_iterator caIt = rawPeciCmd.find("ClientAddress");
5011da66f75SEd Tanous         if (caIt == rawPeciCmd.end())
5021da66f75SEd Tanous         {
5031da66f75SEd Tanous             messages::addMessageToJson(
5041da66f75SEd Tanous                 res.jsonValue, messages::propertyMissing("ClientAddress"),
5051da66f75SEd Tanous                 "/ClientAddress");
5061da66f75SEd Tanous             res.result(boost::beast::http::status::bad_request);
5071da66f75SEd Tanous             res.end();
5081da66f75SEd Tanous             return;
5091da66f75SEd Tanous         }
5101da66f75SEd Tanous         const uint64_t *ca = caIt->get_ptr<const uint64_t *>();
5111da66f75SEd Tanous         if (ca == nullptr)
5121da66f75SEd Tanous         {
5131da66f75SEd Tanous             messages::addMessageToJson(
5141da66f75SEd Tanous                 res.jsonValue,
5151da66f75SEd Tanous                 messages::propertyValueTypeError(caIt->dump(), "ClientAddress"),
5161da66f75SEd Tanous                 "/ClientAddress");
5171da66f75SEd Tanous             res.result(boost::beast::http::status::bad_request);
5181da66f75SEd Tanous             res.end();
5191da66f75SEd Tanous             return;
5201da66f75SEd Tanous         }
5211da66f75SEd Tanous         // Get the Read Length from the request
5221da66f75SEd Tanous         const uint8_t clientAddress = static_cast<uint8_t>(*ca);
5231da66f75SEd Tanous         nlohmann::json::const_iterator rlIt = rawPeciCmd.find("ReadLength");
5241da66f75SEd Tanous         if (rlIt == rawPeciCmd.end())
5251da66f75SEd Tanous         {
5261da66f75SEd Tanous             messages::addMessageToJson(res.jsonValue,
5271da66f75SEd Tanous                                        messages::propertyMissing("ReadLength"),
5281da66f75SEd Tanous                                        "/ReadLength");
5291da66f75SEd Tanous             res.result(boost::beast::http::status::bad_request);
5301da66f75SEd Tanous             res.end();
5311da66f75SEd Tanous             return;
5321da66f75SEd Tanous         }
5331da66f75SEd Tanous         const uint64_t *rl = rlIt->get_ptr<const uint64_t *>();
5341da66f75SEd Tanous         if (rl == nullptr)
5351da66f75SEd Tanous         {
5361da66f75SEd Tanous             messages::addMessageToJson(
5371da66f75SEd Tanous                 res.jsonValue,
5381da66f75SEd Tanous                 messages::propertyValueTypeError(rlIt->dump(), "ReadLength"),
5391da66f75SEd Tanous                 "/ReadLength");
5401da66f75SEd Tanous             res.result(boost::beast::http::status::bad_request);
5411da66f75SEd Tanous             res.end();
5421da66f75SEd Tanous             return;
5431da66f75SEd Tanous         }
5441da66f75SEd Tanous         // Get the PECI Command from the request
5451da66f75SEd Tanous         const uint32_t readLength = static_cast<uint32_t>(*rl);
5461da66f75SEd Tanous         nlohmann::json::const_iterator pcIt = rawPeciCmd.find("PECICommand");
5471da66f75SEd Tanous         if (pcIt == rawPeciCmd.end())
5481da66f75SEd Tanous         {
5491da66f75SEd Tanous             messages::addMessageToJson(res.jsonValue,
5501da66f75SEd Tanous                                        messages::propertyMissing("PECICommand"),
5511da66f75SEd Tanous                                        "/PECICommand");
5521da66f75SEd Tanous             res.result(boost::beast::http::status::bad_request);
5531da66f75SEd Tanous             res.end();
5541da66f75SEd Tanous             return;
5551da66f75SEd Tanous         }
5561da66f75SEd Tanous         std::vector<uint8_t> peciCommand;
5571da66f75SEd Tanous         for (auto pc : *pcIt)
5581da66f75SEd Tanous         {
5591da66f75SEd Tanous             const uint64_t *val = pc.get_ptr<const uint64_t *>();
5601da66f75SEd Tanous             if (val == nullptr)
5611da66f75SEd Tanous             {
5621da66f75SEd Tanous                 messages::addMessageToJson(
5631da66f75SEd Tanous                     res.jsonValue,
5641da66f75SEd Tanous                     messages::propertyValueTypeError(
5651da66f75SEd Tanous                         pc.dump(),
5661da66f75SEd Tanous                         "PECICommand/" + std::to_string(peciCommand.size())),
5671da66f75SEd Tanous                     "/PECICommand");
5681da66f75SEd Tanous                 res.result(boost::beast::http::status::bad_request);
5691da66f75SEd Tanous                 res.end();
5701da66f75SEd Tanous                 return;
5711da66f75SEd Tanous             }
5721da66f75SEd Tanous             peciCommand.push_back(static_cast<uint8_t>(*val));
5731da66f75SEd Tanous         }
5741da66f75SEd Tanous         // Callback to return the Raw PECI response
5751da66f75SEd Tanous         auto sendRawPeciCallback = [&res](const boost::system::error_code ec,
5761da66f75SEd Tanous                                           const std::vector<uint8_t> &resp) {
5771da66f75SEd Tanous             if (ec)
5781da66f75SEd Tanous             {
5791da66f75SEd Tanous                 BMCWEB_LOG_DEBUG << "failed to send PECI command ec: "
5801da66f75SEd Tanous                                  << ec.message();
5811da66f75SEd Tanous                 res.result(boost::beast::http::status::internal_server_error);
5821da66f75SEd Tanous                 res.end();
5831da66f75SEd Tanous                 return;
5841da66f75SEd Tanous             }
5851da66f75SEd Tanous             res.jsonValue = {{"Name", "PECI Command Response"},
5861da66f75SEd Tanous                              {"PECIResponse", resp}};
5871da66f75SEd Tanous             res.end();
5881da66f75SEd Tanous         };
5891da66f75SEd Tanous         // Call the SendRawPECI command with the provided data
5901da66f75SEd Tanous         crow::connections::systemBus->async_method_call(
591*4ed77cd5SEd Tanous             std::move(sendRawPeciCallback), cpuLogObject, cpuLogPath,
592*4ed77cd5SEd Tanous             cpuLogRawPeciInterface, "SendRawPeci", clientAddress, readLength,
593*4ed77cd5SEd Tanous             peciCommand);
5941da66f75SEd Tanous     }
5951da66f75SEd Tanous };
5961da66f75SEd Tanous 
5971da66f75SEd Tanous } // namespace redfish
598