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> ¶ms) 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> ¶ms) 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> ¶ms) 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> ¶ms) 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> ¶ms) 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> ¶ms) 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