1729dae72SJennifer Lee /* 2729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation 3729dae72SJennifer Lee // 4729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License"); 5729dae72SJennifer Lee // you may not use this file except in compliance with the License. 6729dae72SJennifer Lee // You may obtain a copy of the License at 7729dae72SJennifer Lee // 8729dae72SJennifer Lee // http://www.apache.org/licenses/LICENSE-2.0 9729dae72SJennifer Lee // 10729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software 11729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS, 12729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13729dae72SJennifer Lee // See the License for the specific language governing permissions and 14729dae72SJennifer Lee // limitations under the License. 15729dae72SJennifer Lee */ 16729dae72SJennifer Lee #pragma once 17729dae72SJennifer Lee 18729dae72SJennifer Lee #include "node.hpp" 191abe55efSEd Tanous 20729dae72SJennifer Lee #include <boost/container/flat_map.hpp> 2187d84729SAndrew Geissler #include <utils/fw_utils.hpp> 22abf2add6SEd Tanous #include <variant> 23729dae72SJennifer Lee 241abe55efSEd Tanous namespace redfish 251abe55efSEd Tanous { 2627826b5fSEd Tanous 270e7de46fSAndrew Geissler // Match signals added on software path 28acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; 290e7de46fSAndrew Geissler // Only allow one update at a time 300e7de46fSAndrew Geissler static bool fwUpdateInProgress = false; 3186adcd6dSAndrew Geissler // Timer for software available 32271584abSEd Tanous static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer; 3386adcd6dSAndrew Geissler 3486adcd6dSAndrew Geissler static void cleanUp() 3586adcd6dSAndrew Geissler { 3686adcd6dSAndrew Geissler fwUpdateInProgress = false; 3786adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 3886adcd6dSAndrew Geissler } 3986adcd6dSAndrew Geissler static void activateImage(const std::string &objPath, 4086adcd6dSAndrew Geissler const std::string &service) 4186adcd6dSAndrew Geissler { 4286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; 4386adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 4486adcd6dSAndrew Geissler [](const boost::system::error_code error_code) { 4586adcd6dSAndrew Geissler if (error_code) 4686adcd6dSAndrew Geissler { 4786adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 4886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); 4986adcd6dSAndrew Geissler } 5086adcd6dSAndrew Geissler }, 5186adcd6dSAndrew Geissler service, objPath, "org.freedesktop.DBus.Properties", "Set", 5286adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation", "RequestedActivation", 5386adcd6dSAndrew Geissler std::variant<std::string>( 5486adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation.RequestedActivations." 5586adcd6dSAndrew Geissler "Active")); 5686adcd6dSAndrew Geissler } 570554c984SAndrew Geissler 580554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 590554c984SAndrew Geissler // then no asyncResp updates will occur 6086adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 6186adcd6dSAndrew Geissler sdbusplus::message::message &m) 6286adcd6dSAndrew Geissler { 6386adcd6dSAndrew Geissler std::vector<std::pair< 6486adcd6dSAndrew Geissler std::string, 6586adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6686adcd6dSAndrew Geissler interfacesProperties; 6786adcd6dSAndrew Geissler 6886adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 6986adcd6dSAndrew Geissler 7086adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 7186adcd6dSAndrew Geissler 7286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7386adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 7486adcd6dSAndrew Geissler { 7586adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7686adcd6dSAndrew Geissler 7786adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 7886adcd6dSAndrew Geissler { 7986adcd6dSAndrew Geissler // Found our interface, disable callbacks 8086adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 8186adcd6dSAndrew Geissler 8286adcd6dSAndrew Geissler // Retrieve service and activate 8386adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 8486adcd6dSAndrew Geissler [objPath, asyncResp]( 8586adcd6dSAndrew Geissler const boost::system::error_code error_code, 8686adcd6dSAndrew Geissler const std::vector<std::pair< 8786adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 8886adcd6dSAndrew Geissler if (error_code) 8986adcd6dSAndrew Geissler { 9086adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 9186adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 9286adcd6dSAndrew Geissler << error_code.message(); 930554c984SAndrew Geissler if (asyncResp) 940554c984SAndrew Geissler { 9586adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 960554c984SAndrew Geissler } 9786adcd6dSAndrew Geissler cleanUp(); 9886adcd6dSAndrew Geissler return; 9986adcd6dSAndrew Geissler } 10086adcd6dSAndrew Geissler // Ensure we only got one service back 10186adcd6dSAndrew Geissler if (objInfo.size() != 1) 10286adcd6dSAndrew Geissler { 10386adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 10486adcd6dSAndrew Geissler << objInfo.size(); 1050554c984SAndrew Geissler if (asyncResp) 1060554c984SAndrew Geissler { 10786adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 1080554c984SAndrew Geissler } 10986adcd6dSAndrew Geissler cleanUp(); 11086adcd6dSAndrew Geissler return; 11186adcd6dSAndrew Geissler } 11286adcd6dSAndrew Geissler // cancel timer only when 11386adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 11486adcd6dSAndrew Geissler // is added 11586adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 11686adcd6dSAndrew Geissler 11786adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 1180554c984SAndrew Geissler if (asyncResp) 1190554c984SAndrew Geissler { 12086adcd6dSAndrew Geissler redfish::messages::success(asyncResp->res); 1210554c984SAndrew Geissler } 12286adcd6dSAndrew Geissler fwUpdateInProgress = false; 12386adcd6dSAndrew Geissler }, 12486adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 12586adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 12686adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 12786adcd6dSAndrew Geissler std::array<const char *, 1>{ 12886adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 12986adcd6dSAndrew Geissler } 13086adcd6dSAndrew Geissler } 13186adcd6dSAndrew Geissler } 13286adcd6dSAndrew Geissler 1330554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 1340554c984SAndrew Geissler // then no asyncResp updates will occur 13586adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 1360554c984SAndrew Geissler const crow::Request &req, 1370554c984SAndrew Geissler int timeoutTimeSeconds = 5) 13886adcd6dSAndrew Geissler { 13986adcd6dSAndrew Geissler // Only allow one FW update at a time 14086adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 14186adcd6dSAndrew Geissler { 1420554c984SAndrew Geissler if (asyncResp) 1430554c984SAndrew Geissler { 14486adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 1450554c984SAndrew Geissler } 14686adcd6dSAndrew Geissler return; 14786adcd6dSAndrew Geissler } 14886adcd6dSAndrew Geissler 1490554c984SAndrew Geissler fwAvailableTimer = 150271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 15186adcd6dSAndrew Geissler 152271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 15386adcd6dSAndrew Geissler 15486adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 15586adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 15686adcd6dSAndrew Geissler cleanUp(); 15786adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 15886adcd6dSAndrew Geissler { 15986adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 16086adcd6dSAndrew Geissler return; 16186adcd6dSAndrew Geissler } 16286adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 16386adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 16486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 16586adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 16686adcd6dSAndrew Geissler if (ec) 16786adcd6dSAndrew Geissler { 16886adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 16986adcd6dSAndrew Geissler return; 17086adcd6dSAndrew Geissler } 1710554c984SAndrew Geissler if (asyncResp) 1720554c984SAndrew Geissler { 17386adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 1740554c984SAndrew Geissler } 17586adcd6dSAndrew Geissler }); 17686adcd6dSAndrew Geissler 17786adcd6dSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 17886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 17986adcd6dSAndrew Geissler softwareInterfaceAdded(asyncResp, m); 18086adcd6dSAndrew Geissler }; 18186adcd6dSAndrew Geissler 18286adcd6dSAndrew Geissler fwUpdateInProgress = true; 18386adcd6dSAndrew Geissler 18486adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 18586adcd6dSAndrew Geissler *crow::connections::systemBus, 18686adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 18786adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 18886adcd6dSAndrew Geissler callback); 18986adcd6dSAndrew Geissler } 190729dae72SJennifer Lee 1910554c984SAndrew Geissler /** 1920554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 1930554c984SAndrew Geissler * SimpleUpdate action. 1940554c984SAndrew Geissler */ 1950554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 1960554c984SAndrew Geissler { 1970554c984SAndrew Geissler public: 1980554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 1990554c984SAndrew Geissler Node(app, 2000554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 2010554c984SAndrew Geissler { 2020554c984SAndrew Geissler entityPrivileges = { 2030554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 2040554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 2050554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 2060554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2070554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2080554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2090554c984SAndrew Geissler } 2100554c984SAndrew Geissler 2110554c984SAndrew Geissler private: 2120554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 2130554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 2140554c984SAndrew Geissler { 2150554c984SAndrew Geissler std::optional<std::string> transferProtocol; 2160554c984SAndrew Geissler std::string imageURI; 2170554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2180554c984SAndrew Geissler 2190554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 2200554c984SAndrew Geissler 2210554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 2220554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 2230554c984SAndrew Geissler // within it. 2240554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 2250554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 2260554c984SAndrew Geissler 2270554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 2280554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 2290554c984SAndrew Geissler { 2300554c984SAndrew Geissler BMCWEB_LOG_DEBUG 2310554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 2320554c984SAndrew Geissler return; 2330554c984SAndrew Geissler } 2340554c984SAndrew Geissler if (!transferProtocol) 2350554c984SAndrew Geissler { 2360554c984SAndrew Geissler // Must be option 2 2370554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 2380554c984SAndrew Geissler size_t separator = imageURI.find(":"); 2390554c984SAndrew Geissler if ((separator == std::string::npos) || 2400554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 2410554c984SAndrew Geissler { 2420554c984SAndrew Geissler messages::actionParameterValueTypeError( 2430554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 2440554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 2450554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 2460554c984SAndrew Geissler << imageURI; 2470554c984SAndrew Geissler return; 2480554c984SAndrew Geissler } 2490554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 2500554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 2510554c984SAndrew Geissler boost::to_upper(*transferProtocol); 2520554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 2530554c984SAndrew Geissler << *transferProtocol; 2540554c984SAndrew Geissler 2550554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 2560554c984SAndrew Geissler // below 2570554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 2580554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 2590554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 2600554c984SAndrew Geissler } 2610554c984SAndrew Geissler 2620554c984SAndrew Geissler // OpenBMC currently only supports TFTP 2630554c984SAndrew Geissler if (*transferProtocol != "TFTP") 2640554c984SAndrew Geissler { 2650554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 2660554c984SAndrew Geissler "TransferProtocol", 2670554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 2680554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 2690554c984SAndrew Geissler << *transferProtocol; 2700554c984SAndrew Geissler return; 2710554c984SAndrew Geissler } 2720554c984SAndrew Geissler 2730554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 2740554c984SAndrew Geissler size_t separator = imageURI.find("/"); 2750554c984SAndrew Geissler if ((separator == std::string::npos) || 2760554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 2770554c984SAndrew Geissler { 2780554c984SAndrew Geissler messages::actionParameterValueTypeError( 2790554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 2800554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 2810554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 2820554c984SAndrew Geissler return; 2830554c984SAndrew Geissler } 2840554c984SAndrew Geissler 2850554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 2860554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 2870554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 2880554c984SAndrew Geissler 2890554c984SAndrew Geissler // Setup callback for when new software detected 2900554c984SAndrew Geissler // Give TFTP 2 minutes to complete 2910554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 2920554c984SAndrew Geissler 2930554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 2940554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 2950554c984SAndrew Geissler // has been started. The callback above will ensure the activate 2960554c984SAndrew Geissler // is started once the download has completed 2970554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 2980554c984SAndrew Geissler 2990554c984SAndrew Geissler // Call TFTP service 3000554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 3010554c984SAndrew Geissler [](const boost::system::error_code ec) { 3020554c984SAndrew Geissler if (ec) 3030554c984SAndrew Geissler { 3040554c984SAndrew Geissler // messages::internalError(asyncResp->res); 3050554c984SAndrew Geissler cleanUp(); 3060554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 3070554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 3080554c984SAndrew Geissler } 3090554c984SAndrew Geissler else 3100554c984SAndrew Geissler { 3110554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 3120554c984SAndrew Geissler } 3130554c984SAndrew Geissler }, 3140554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 3150554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 3160554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 3170554c984SAndrew Geissler 3180554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 3190554c984SAndrew Geissler } 3200554c984SAndrew Geissler }; 3210554c984SAndrew Geissler 3221abe55efSEd Tanous class UpdateService : public Node 3231abe55efSEd Tanous { 324729dae72SJennifer Lee public: 3251abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 3261abe55efSEd Tanous { 327729dae72SJennifer Lee entityPrivileges = { 328729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 329729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 330729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 331729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 332729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 333729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 334729dae72SJennifer Lee } 335729dae72SJennifer Lee 336729dae72SJennifer Lee private: 33755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 3381abe55efSEd Tanous const std::vector<std::string> ¶ms) override 3391abe55efSEd Tanous { 340274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 341274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 3420f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 3430f74e643SEd Tanous res.jsonValue["@odata.context"] = 3440f74e643SEd Tanous "/redfish/v1/$metadata#UpdateService.UpdateService"; 3450f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 3460f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 3470f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 3480f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 3490f74e643SEd Tanous // UpdateService cannot be disabled 3500f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 3510f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 3520f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 3530554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 3540554c984SAndrew Geissler // Update Actions object. 3550554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 3560554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 3570554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 3580554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 3590554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 3600554c984SAndrew Geissler "TFTP"}; 3610554c984SAndrew Geissler #endif 362274dfe62SJayashankar Padath // Get the current ApplyTime value 363274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 364274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 365274dfe62SJayashankar Padath const std::variant<std::string> &applyTime) { 366274dfe62SJayashankar Padath if (ec) 367274dfe62SJayashankar Padath { 368274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 369274dfe62SJayashankar Padath messages::internalError(aResp->res); 370274dfe62SJayashankar Padath return; 371274dfe62SJayashankar Padath } 372274dfe62SJayashankar Padath 373274dfe62SJayashankar Padath const std::string *s = std::get_if<std::string>(&applyTime); 374274dfe62SJayashankar Padath if (s == nullptr) 375274dfe62SJayashankar Padath { 376274dfe62SJayashankar Padath return; 377274dfe62SJayashankar Padath } 378274dfe62SJayashankar Padath // Store the ApplyTime Value 379274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 380274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 381274dfe62SJayashankar Padath { 382274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 383274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 384274dfe62SJayashankar Padath "Immediate"; 385274dfe62SJayashankar Padath } 386274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 387274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 388274dfe62SJayashankar Padath { 389274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 390274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 391274dfe62SJayashankar Padath "OnReset"; 392274dfe62SJayashankar Padath } 393274dfe62SJayashankar Padath }, 394274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 395274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 396274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 397274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 398729dae72SJennifer Lee } 3990e7de46fSAndrew Geissler 400fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 401fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 402fa1a5a38SJayashankar Padath { 403fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 404fa1a5a38SJayashankar Padath 405fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 406fa1a5a38SJayashankar Padath 407274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 408274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 409274dfe62SJayashankar Padath pushUriOptions)) 410fa1a5a38SJayashankar Padath { 411fa1a5a38SJayashankar Padath return; 412fa1a5a38SJayashankar Padath } 413fa1a5a38SJayashankar Padath 414274dfe62SJayashankar Padath if (pushUriOptions) 415274dfe62SJayashankar Padath { 416274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 417274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 418274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 419274dfe62SJayashankar Padath { 420274dfe62SJayashankar Padath return; 421274dfe62SJayashankar Padath } 422274dfe62SJayashankar Padath 423274dfe62SJayashankar Padath if (pushUriApplyTime) 424274dfe62SJayashankar Padath { 425274dfe62SJayashankar Padath std::optional<std::string> applyTime; 426274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 427274dfe62SJayashankar Padath applyTime)) 428274dfe62SJayashankar Padath { 429274dfe62SJayashankar Padath return; 430274dfe62SJayashankar Padath } 431274dfe62SJayashankar Padath 432274dfe62SJayashankar Padath if (applyTime) 433fa1a5a38SJayashankar Padath { 434fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 435fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 436fa1a5a38SJayashankar Padath { 437274dfe62SJayashankar Padath applyTimeNewVal = 438274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 439fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 440fa1a5a38SJayashankar Padath } 441274dfe62SJayashankar Padath else if (applyTime == "OnReset") 442274dfe62SJayashankar Padath { 443274dfe62SJayashankar Padath applyTimeNewVal = 444274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 445274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 446274dfe62SJayashankar Padath } 447fa1a5a38SJayashankar Padath else 448fa1a5a38SJayashankar Padath { 449274dfe62SJayashankar Padath BMCWEB_LOG_INFO 450274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 451274dfe62SJayashankar Padath "acceptable values"; 452274dfe62SJayashankar Padath messages::propertyValueNotInList( 453274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 454274dfe62SJayashankar Padath return; 455fa1a5a38SJayashankar Padath } 456fa1a5a38SJayashankar Padath 457fa1a5a38SJayashankar Padath // Set the requested image apply time value 458fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 459fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 460fa1a5a38SJayashankar Padath if (ec) 461fa1a5a38SJayashankar Padath { 462274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 463274dfe62SJayashankar Padath << ec; 464fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 465fa1a5a38SJayashankar Padath return; 466fa1a5a38SJayashankar Padath } 467fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 468fa1a5a38SJayashankar Padath }, 469fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 470fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 471fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 472274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 473274dfe62SJayashankar Padath "RequestedApplyTime", 474fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 475fa1a5a38SJayashankar Padath } 476274dfe62SJayashankar Padath } 477fa1a5a38SJayashankar Padath } 478fa1a5a38SJayashankar Padath } 479fa1a5a38SJayashankar Padath 480acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 4811abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4821abe55efSEd Tanous { 483acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 484acb7cfb4SJennifer Lee 4850e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 486acb7cfb4SJennifer Lee 48786adcd6dSAndrew Geissler // Setup callback for when new software detected 48886adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 489acb7cfb4SJennifer Lee 490acb7cfb4SJennifer Lee std::string filepath( 491acb7cfb4SJennifer Lee "/tmp/images/" + 492acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 493acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 494acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 495acb7cfb4SJennifer Lee std::ofstream::trunc); 496acb7cfb4SJennifer Lee out << req.body; 497acb7cfb4SJennifer Lee out.close(); 498acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 499acb7cfb4SJennifer Lee } 500729dae72SJennifer Lee }; 501729dae72SJennifer Lee 5021abe55efSEd Tanous class SoftwareInventoryCollection : public Node 5031abe55efSEd Tanous { 504729dae72SJennifer Lee public: 505729dae72SJennifer Lee template <typename CrowApp> 5061abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 5071abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 5081abe55efSEd Tanous { 509729dae72SJennifer Lee entityPrivileges = { 510729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 511729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 512729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 513729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 514729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 515729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 516729dae72SJennifer Lee } 517729dae72SJennifer Lee 518729dae72SJennifer Lee private: 51955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 5201abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5211abe55efSEd Tanous { 522c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 5230f74e643SEd Tanous res.jsonValue["@odata.type"] = 5240f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 5250f74e643SEd Tanous res.jsonValue["@odata.id"] = 5260f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 5270f74e643SEd Tanous res.jsonValue["@odata.context"] = 5280f74e643SEd Tanous "/redfish/v1/" 5290f74e643SEd Tanous "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 5300f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 531c711bf86SEd Tanous 532c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 533c711bf86SEd Tanous [asyncResp]( 534c711bf86SEd Tanous const boost::system::error_code ec, 5356c4eb9deSJennifer Lee const std::vector<std::pair< 5361abe55efSEd Tanous std::string, std::vector<std::pair< 5371abe55efSEd Tanous std::string, std::vector<std::string>>>>> 5386c4eb9deSJennifer Lee &subtree) { 5391abe55efSEd Tanous if (ec) 5401abe55efSEd Tanous { 541f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5426c4eb9deSJennifer Lee return; 543729dae72SJennifer Lee } 544c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 545c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 5466c4eb9deSJennifer Lee 5471abe55efSEd Tanous for (auto &obj : subtree) 5481abe55efSEd Tanous { 549f4b65ab1SJennifer Lee // if can't parse fw id then return 55027826b5fSEd Tanous std::size_t idPos; 55127826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 552f4b65ab1SJennifer Lee { 553f12894f8SJason M. Bills messages::internalError(asyncResp->res); 554f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 555f4b65ab1SJennifer Lee return; 556f4b65ab1SJennifer Lee } 557f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 558f4b65ab1SJennifer Lee 559c711bf86SEd Tanous nlohmann::json &members = 560c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 561c711bf86SEd Tanous members.push_back( 562f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 5631abe55efSEd Tanous "FirmwareInventory/" + 564f4b65ab1SJennifer Lee swId}}); 565e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 566c711bf86SEd Tanous members.size(); 5676c4eb9deSJennifer Lee } 568c711bf86SEd Tanous }, 569*2830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 570*2830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 571*2830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 572*2830a9cfSAndrew Geissler // path must be used here as input to mapper 573c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 574c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 575*2830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 576*2830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 5771abe55efSEd Tanous std::array<const char *, 1>{ 5781abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 579729dae72SJennifer Lee } 580729dae72SJennifer Lee }; 581c711bf86SEd Tanous 5821abe55efSEd Tanous class SoftwareInventory : public Node 5831abe55efSEd Tanous { 584729dae72SJennifer Lee public: 585729dae72SJennifer Lee template <typename CrowApp> 5861abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 5871abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 5881abe55efSEd Tanous std::string()) 5891abe55efSEd Tanous { 590729dae72SJennifer Lee entityPrivileges = { 591729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 592729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 593729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 594729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 595729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 596729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 597729dae72SJennifer Lee } 598729dae72SJennifer Lee 599729dae72SJennifer Lee private: 60087d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 60187d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 60287d84729SAndrew Geissler const std::string &purpose) 60387d84729SAndrew Geissler { 60487d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 60587d84729SAndrew Geissler { 60687d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 60787d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 60887d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 60987d84729SAndrew Geissler } 61087d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 61187d84729SAndrew Geissler { 61287d84729SAndrew Geissler // TODO(geissonator) Need BIOS schema support added for this 61387d84729SAndrew Geissler // to be valid 61487d84729SAndrew Geissler // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 61587d84729SAndrew Geissler // members.push_back( 61687d84729SAndrew Geissler // {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}}); 61787d84729SAndrew Geissler // aResp->res.jsonValue["Members@odata.count"] = members.size(); 61887d84729SAndrew Geissler } 61987d84729SAndrew Geissler else 62087d84729SAndrew Geissler { 62187d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 62287d84729SAndrew Geissler } 62387d84729SAndrew Geissler } 62487d84729SAndrew Geissler 62555c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6261abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6271abe55efSEd Tanous { 628c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6296c4eb9deSJennifer Lee 6301abe55efSEd Tanous if (params.size() != 1) 6311abe55efSEd Tanous { 632f12894f8SJason M. Bills messages::internalError(res); 633729dae72SJennifer Lee res.end(); 634729dae72SJennifer Lee return; 635729dae72SJennifer Lee } 636729dae72SJennifer Lee 6373ae837c9SEd Tanous std::shared_ptr<std::string> swId = 638c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 639c711bf86SEd Tanous 64055c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 6413ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 642c711bf86SEd Tanous 643c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 6443ae837c9SEd Tanous [asyncResp, swId]( 645c711bf86SEd Tanous const boost::system::error_code ec, 6466c4eb9deSJennifer Lee const std::vector<std::pair< 6471abe55efSEd Tanous std::string, std::vector<std::pair< 6481abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6496c4eb9deSJennifer Lee &subtree) { 65055c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 6511abe55efSEd Tanous if (ec) 6521abe55efSEd Tanous { 653f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6546c4eb9deSJennifer Lee return; 6556c4eb9deSJennifer Lee } 6566c4eb9deSJennifer Lee 6576913228dSAndrew Geissler // Ensure we find our input swId, otherwise return an error 6586913228dSAndrew Geissler bool found = false; 6591abe55efSEd Tanous for (const std::pair< 6601abe55efSEd Tanous std::string, 6611abe55efSEd Tanous std::vector< 6621abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 6631abe55efSEd Tanous &obj : subtree) 6641abe55efSEd Tanous { 6653ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 6661abe55efSEd Tanous { 667acb7cfb4SJennifer Lee continue; 668acb7cfb4SJennifer Lee } 669acb7cfb4SJennifer Lee 670f4b65ab1SJennifer Lee if (obj.second.size() < 1) 6711abe55efSEd Tanous { 672acb7cfb4SJennifer Lee continue; 673acb7cfb4SJennifer Lee } 6746c4eb9deSJennifer Lee 6756913228dSAndrew Geissler found = true; 676e0dd8057SAndrew Geissler fw_util::getFwStatus(asyncResp, swId, obj.second[0].first); 677e0dd8057SAndrew Geissler 67855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6791abe55efSEd Tanous [asyncResp, 6803ae837c9SEd Tanous swId](const boost::system::error_code error_code, 6811abe55efSEd Tanous const boost::container::flat_map< 6821abe55efSEd Tanous std::string, VariantType> &propertiesList) { 6831abe55efSEd Tanous if (error_code) 6841abe55efSEd Tanous { 685f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6866c4eb9deSJennifer Lee return; 6876c4eb9deSJennifer Lee } 6881abe55efSEd Tanous boost::container::flat_map< 6891abe55efSEd Tanous std::string, VariantType>::const_iterator it = 6906c4eb9deSJennifer Lee propertiesList.find("Purpose"); 6911abe55efSEd Tanous if (it == propertiesList.end()) 6921abe55efSEd Tanous { 6931abe55efSEd Tanous BMCWEB_LOG_DEBUG 6941abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 695f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 696f12894f8SJason M. Bills "Purpose"); 6976c4eb9deSJennifer Lee return; 6986c4eb9deSJennifer Lee } 6993ae837c9SEd Tanous const std::string *swInvPurpose = 700abf2add6SEd Tanous std::get_if<std::string>(&it->second); 7013ae837c9SEd Tanous if (swInvPurpose == nullptr) 7021abe55efSEd Tanous { 7031abe55efSEd Tanous BMCWEB_LOG_DEBUG 7041abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 705f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 706f12894f8SJason M. Bills "", "Purpose"); 707acb7cfb4SJennifer Lee return; 708acb7cfb4SJennifer Lee } 709c711bf86SEd Tanous 7103ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 7113ae837c9SEd Tanous << *swInvPurpose; 712c711bf86SEd Tanous it = propertiesList.find("Version"); 7131abe55efSEd Tanous if (it == propertiesList.end()) 7141abe55efSEd Tanous { 7151abe55efSEd Tanous BMCWEB_LOG_DEBUG 7161abe55efSEd Tanous << "Can't find property \"Version\"!"; 717f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 718f12894f8SJason M. Bills "Version"); 719c711bf86SEd Tanous return; 720acb7cfb4SJennifer Lee } 721acb7cfb4SJennifer Lee 722f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 723c711bf86SEd Tanous 724f4b65ab1SJennifer Lee const std::string *version = 725abf2add6SEd Tanous std::get_if<std::string>(&it->second); 726f4b65ab1SJennifer Lee 727f4b65ab1SJennifer Lee if (version == nullptr) 7281abe55efSEd Tanous { 7291abe55efSEd Tanous BMCWEB_LOG_DEBUG 7301abe55efSEd Tanous << "Can't find property \"Version\"!"; 731f12894f8SJason M. Bills 732f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 733f12894f8SJason M. Bills "", "Version"); 7346c4eb9deSJennifer Lee return; 7356c4eb9deSJennifer Lee } 736c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 7373ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 73854daabe7SAndrew Geissler 73954daabe7SAndrew Geissler // swInvPurpose is of format: 74054daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 741e2e96770SJames Feist // Translate this to "ABC image" 74254daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 74354daabe7SAndrew Geissler if (endDesc == std::string::npos) 74454daabe7SAndrew Geissler { 74554daabe7SAndrew Geissler messages::internalError(asyncResp->res); 74654daabe7SAndrew Geissler return; 74754daabe7SAndrew Geissler } 74854daabe7SAndrew Geissler endDesc++; 74954daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 75054daabe7SAndrew Geissler { 75154daabe7SAndrew Geissler messages::internalError(asyncResp->res); 75254daabe7SAndrew Geissler return; 75354daabe7SAndrew Geissler } 75454daabe7SAndrew Geissler 75554daabe7SAndrew Geissler std::string formatDesc = 75654daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 75754daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 758e2e96770SJames Feist formatDesc + " image"; 75987d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 7606c4eb9deSJennifer Lee }, 761c711bf86SEd Tanous obj.second[0].first, obj.first, 762c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 763c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 7646c4eb9deSJennifer Lee } 7656913228dSAndrew Geissler if (!found) 7666913228dSAndrew Geissler { 7676913228dSAndrew Geissler BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!"; 7686913228dSAndrew Geissler messages::resourceMissingAtURI( 7696913228dSAndrew Geissler asyncResp->res, 7706913228dSAndrew Geissler "/redfish/v1/UpdateService/FirmwareInventory/" + *swId); 7716913228dSAndrew Geissler return; 7726913228dSAndrew Geissler } 7734e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.type"] = 7744e68c45bSAyushi Smriti "#SoftwareInventory.v1_1_0.SoftwareInventory"; 7754e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.context"] = 7764e68c45bSAyushi Smriti "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 7774e68c45bSAyushi Smriti asyncResp->res.jsonValue["Name"] = "Software Inventory"; 7784e68c45bSAyushi Smriti asyncResp->res.jsonValue["Updateable"] = false; 7794e68c45bSAyushi Smriti asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK"; 780c711bf86SEd Tanous }, 781c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 782c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 783271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 784271584abSEd Tanous static_cast<int32_t>(0), 7851abe55efSEd Tanous std::array<const char *, 1>{ 7861abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 7876c4eb9deSJennifer Lee } 788729dae72SJennifer Lee }; 789729dae72SJennifer Lee 790729dae72SJennifer Lee } // namespace redfish 791