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 { 120*32898ceaSJames Feist std::shared_ptr<task::TaskData> task = 121*32898ceaSJames Feist task::TaskData::createTask( 122*32898ceaSJames Feist [](boost::system::error_code ec, 123*32898ceaSJames Feist sdbusplus::message::message &msg, 124*32898ceaSJames Feist const std::shared_ptr<task::TaskData> 125*32898ceaSJames Feist &taskData) { 126*32898ceaSJames Feist if (ec) 127*32898ceaSJames Feist { 128*32898ceaSJames Feist return task::completed; 129*32898ceaSJames Feist } 130*32898ceaSJames Feist 131*32898ceaSJames Feist std::string iface; 132*32898ceaSJames Feist boost::container::flat_map< 133*32898ceaSJames Feist std::string, std::variant<std::string>> 134*32898ceaSJames Feist values; 135*32898ceaSJames Feist msg.read(iface, values); 136*32898ceaSJames Feist auto findActivation = 137*32898ceaSJames Feist values.find("Activation"); 138*32898ceaSJames Feist if (findActivation == values.end()) 139*32898ceaSJames Feist { 140*32898ceaSJames Feist return !task::completed; 141*32898ceaSJames Feist } 142*32898ceaSJames Feist std::string *state = 143*32898ceaSJames Feist std::get_if<std::string>( 144*32898ceaSJames Feist &(findActivation->second)); 145*32898ceaSJames Feist 146*32898ceaSJames Feist if (state == nullptr) 147*32898ceaSJames Feist { 148*32898ceaSJames Feist taskData->messages.emplace_back( 149*32898ceaSJames Feist messages::internalError()); 150*32898ceaSJames Feist return task::completed; 151*32898ceaSJames Feist } 152*32898ceaSJames Feist 153*32898ceaSJames Feist if (boost::ends_with(*state, "Invalid") || 154*32898ceaSJames Feist boost::ends_with(*state, "Failed")) 155*32898ceaSJames Feist { 156*32898ceaSJames Feist taskData->state = "Exception"; 157*32898ceaSJames Feist taskData->status = "Warning"; 158*32898ceaSJames Feist taskData->messages.emplace_back( 159*32898ceaSJames Feist messages::invalidObject( 160*32898ceaSJames Feist "/redfish/v1/UpdateService/")); 161*32898ceaSJames Feist return task::completed; 162*32898ceaSJames Feist } 163*32898ceaSJames Feist 164*32898ceaSJames Feist if (boost::ends_with(*state, "Staged")) 165*32898ceaSJames Feist { 166*32898ceaSJames Feist taskData->state = "Pending"; 167*32898ceaSJames Feist return !task::completed; 168*32898ceaSJames Feist } 169*32898ceaSJames Feist 170*32898ceaSJames Feist if (boost::ends_with(*state, "Active")) 171*32898ceaSJames Feist { 172*32898ceaSJames Feist taskData->messages.emplace_back( 173*32898ceaSJames Feist messages::success()); 174*32898ceaSJames Feist taskData->state = "Completed"; 175*32898ceaSJames Feist return task::completed; 176*32898ceaSJames Feist } 177*32898ceaSJames Feist 178*32898ceaSJames Feist // as firmware update often results in a 179*32898ceaSJames Feist // reboot, the task may never "complete" 180*32898ceaSJames Feist // unless it is an error 181*32898ceaSJames Feist 182*32898ceaSJames Feist return !task::completed; 183*32898ceaSJames Feist }, 184*32898ceaSJames Feist "type='signal',interface='org.freedesktop.DBus." 185*32898ceaSJames Feist "Properties'," 186*32898ceaSJames Feist "member='PropertiesChanged',arg0='xyz.openbmc_" 187*32898ceaSJames Feist "project.Software.Activation',path='" + 188*32898ceaSJames Feist objPath.str + "'"); 189*32898ceaSJames Feist task->startTimer(std::chrono::minutes(5)); 190*32898ceaSJames Feist task->populateResp(asyncResp->res); 1910554c984SAndrew Geissler } 19286adcd6dSAndrew Geissler fwUpdateInProgress = false; 19386adcd6dSAndrew Geissler }, 19486adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 19586adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 19686adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 19786adcd6dSAndrew Geissler std::array<const char *, 1>{ 19886adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 19986adcd6dSAndrew Geissler } 20086adcd6dSAndrew Geissler } 20186adcd6dSAndrew Geissler } 20286adcd6dSAndrew Geissler 2030554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 2040554c984SAndrew Geissler // then no asyncResp updates will occur 20586adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 2060554c984SAndrew Geissler const crow::Request &req, 2070554c984SAndrew Geissler int timeoutTimeSeconds = 5) 20886adcd6dSAndrew Geissler { 20986adcd6dSAndrew Geissler // Only allow one FW update at a time 21086adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 21186adcd6dSAndrew Geissler { 2120554c984SAndrew Geissler if (asyncResp) 2130554c984SAndrew Geissler { 21486adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 2150554c984SAndrew Geissler } 21686adcd6dSAndrew Geissler return; 21786adcd6dSAndrew Geissler } 21886adcd6dSAndrew Geissler 2190554c984SAndrew Geissler fwAvailableTimer = 220271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 22186adcd6dSAndrew Geissler 222271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 22386adcd6dSAndrew Geissler 22486adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 22586adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 22686adcd6dSAndrew Geissler cleanUp(); 22786adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 22886adcd6dSAndrew Geissler { 22986adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 23086adcd6dSAndrew Geissler return; 23186adcd6dSAndrew Geissler } 23286adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23386adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 23486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 23586adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 23686adcd6dSAndrew Geissler if (ec) 23786adcd6dSAndrew Geissler { 23886adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 23986adcd6dSAndrew Geissler return; 24086adcd6dSAndrew Geissler } 2410554c984SAndrew Geissler if (asyncResp) 2420554c984SAndrew Geissler { 24386adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 2440554c984SAndrew Geissler } 24586adcd6dSAndrew Geissler }); 24686adcd6dSAndrew Geissler 24786adcd6dSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 24886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 24986adcd6dSAndrew Geissler softwareInterfaceAdded(asyncResp, m); 25086adcd6dSAndrew Geissler }; 25186adcd6dSAndrew Geissler 25286adcd6dSAndrew Geissler fwUpdateInProgress = true; 25386adcd6dSAndrew Geissler 25486adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 25586adcd6dSAndrew Geissler *crow::connections::systemBus, 25686adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 25786adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 25886adcd6dSAndrew Geissler callback); 25986adcd6dSAndrew Geissler } 260729dae72SJennifer Lee 2610554c984SAndrew Geissler /** 2620554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 2630554c984SAndrew Geissler * SimpleUpdate action. 2640554c984SAndrew Geissler */ 2650554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 2660554c984SAndrew Geissler { 2670554c984SAndrew Geissler public: 2680554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 2690554c984SAndrew Geissler Node(app, 2700554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 2710554c984SAndrew Geissler { 2720554c984SAndrew Geissler entityPrivileges = { 2730554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 2740554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 2750554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 2760554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2770554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2780554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2790554c984SAndrew Geissler } 2800554c984SAndrew Geissler 2810554c984SAndrew Geissler private: 2820554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 2830554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 2840554c984SAndrew Geissler { 2850554c984SAndrew Geissler std::optional<std::string> transferProtocol; 2860554c984SAndrew Geissler std::string imageURI; 2870554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2880554c984SAndrew Geissler 2890554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 2900554c984SAndrew Geissler 2910554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 2920554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 2930554c984SAndrew Geissler // within it. 2940554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 2950554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 2960554c984SAndrew Geissler 2970554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 2980554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 2990554c984SAndrew Geissler { 3000554c984SAndrew Geissler BMCWEB_LOG_DEBUG 3010554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 3020554c984SAndrew Geissler return; 3030554c984SAndrew Geissler } 3040554c984SAndrew Geissler if (!transferProtocol) 3050554c984SAndrew Geissler { 3060554c984SAndrew Geissler // Must be option 2 3070554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 3080554c984SAndrew Geissler size_t separator = imageURI.find(":"); 3090554c984SAndrew Geissler if ((separator == std::string::npos) || 3100554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3110554c984SAndrew Geissler { 3120554c984SAndrew Geissler messages::actionParameterValueTypeError( 3130554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3140554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3150554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 3160554c984SAndrew Geissler << imageURI; 3170554c984SAndrew Geissler return; 3180554c984SAndrew Geissler } 3190554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 3200554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 3210554c984SAndrew Geissler boost::to_upper(*transferProtocol); 3220554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 3230554c984SAndrew Geissler << *transferProtocol; 3240554c984SAndrew Geissler 3250554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 3260554c984SAndrew Geissler // below 3270554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 3280554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 3290554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 3300554c984SAndrew Geissler } 3310554c984SAndrew Geissler 3320554c984SAndrew Geissler // OpenBMC currently only supports TFTP 3330554c984SAndrew Geissler if (*transferProtocol != "TFTP") 3340554c984SAndrew Geissler { 3350554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 3360554c984SAndrew Geissler "TransferProtocol", 3370554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3380554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 3390554c984SAndrew Geissler << *transferProtocol; 3400554c984SAndrew Geissler return; 3410554c984SAndrew Geissler } 3420554c984SAndrew Geissler 3430554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 3440554c984SAndrew Geissler size_t separator = imageURI.find("/"); 3450554c984SAndrew Geissler if ((separator == std::string::npos) || 3460554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3470554c984SAndrew Geissler { 3480554c984SAndrew Geissler messages::actionParameterValueTypeError( 3490554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3500554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3510554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 3520554c984SAndrew Geissler return; 3530554c984SAndrew Geissler } 3540554c984SAndrew Geissler 3550554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 3560554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 3570554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 3580554c984SAndrew Geissler 3590554c984SAndrew Geissler // Setup callback for when new software detected 3600554c984SAndrew Geissler // Give TFTP 2 minutes to complete 3610554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 3620554c984SAndrew Geissler 3630554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 3640554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 3650554c984SAndrew Geissler // has been started. The callback above will ensure the activate 3660554c984SAndrew Geissler // is started once the download has completed 3670554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 3680554c984SAndrew Geissler 3690554c984SAndrew Geissler // Call TFTP service 3700554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 3710554c984SAndrew Geissler [](const boost::system::error_code ec) { 3720554c984SAndrew Geissler if (ec) 3730554c984SAndrew Geissler { 3740554c984SAndrew Geissler // messages::internalError(asyncResp->res); 3750554c984SAndrew Geissler cleanUp(); 3760554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 3770554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 3780554c984SAndrew Geissler } 3790554c984SAndrew Geissler else 3800554c984SAndrew Geissler { 3810554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 3820554c984SAndrew Geissler } 3830554c984SAndrew Geissler }, 3840554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 3850554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 3860554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 3870554c984SAndrew Geissler 3880554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 3890554c984SAndrew Geissler } 3900554c984SAndrew Geissler }; 3910554c984SAndrew Geissler 3921abe55efSEd Tanous class UpdateService : public Node 3931abe55efSEd Tanous { 394729dae72SJennifer Lee public: 3951abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 3961abe55efSEd Tanous { 397729dae72SJennifer Lee entityPrivileges = { 398729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 399729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 400729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 401729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 402729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 403729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 404729dae72SJennifer Lee } 405729dae72SJennifer Lee 406729dae72SJennifer Lee private: 40755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 4081abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4091abe55efSEd Tanous { 410274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 411274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 4120f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 4130f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 4140f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 4150f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 4160f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 4170f74e643SEd Tanous // UpdateService cannot be disabled 4180f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 4190f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 4200f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 4210554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 4220554c984SAndrew Geissler // Update Actions object. 4230554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 4240554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 4250554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 4260554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 4270554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 4280554c984SAndrew Geissler "TFTP"}; 4290554c984SAndrew Geissler #endif 430274dfe62SJayashankar Padath // Get the current ApplyTime value 431274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 432274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 433274dfe62SJayashankar Padath const std::variant<std::string> &applyTime) { 434274dfe62SJayashankar Padath if (ec) 435274dfe62SJayashankar Padath { 436274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 437274dfe62SJayashankar Padath messages::internalError(aResp->res); 438274dfe62SJayashankar Padath return; 439274dfe62SJayashankar Padath } 440274dfe62SJayashankar Padath 441274dfe62SJayashankar Padath const std::string *s = std::get_if<std::string>(&applyTime); 442274dfe62SJayashankar Padath if (s == nullptr) 443274dfe62SJayashankar Padath { 444274dfe62SJayashankar Padath return; 445274dfe62SJayashankar Padath } 446274dfe62SJayashankar Padath // Store the ApplyTime Value 447274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 448274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 449274dfe62SJayashankar Padath { 450274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 451274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 452274dfe62SJayashankar Padath "Immediate"; 453274dfe62SJayashankar Padath } 454274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 455274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 456274dfe62SJayashankar Padath { 457274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 458274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 459274dfe62SJayashankar Padath "OnReset"; 460274dfe62SJayashankar Padath } 461274dfe62SJayashankar Padath }, 462274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 463274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 464274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 465274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 466729dae72SJennifer Lee } 4670e7de46fSAndrew Geissler 468fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 469fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 470fa1a5a38SJayashankar Padath { 471fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 472fa1a5a38SJayashankar Padath 473fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 474fa1a5a38SJayashankar Padath 475274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 476274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 477274dfe62SJayashankar Padath pushUriOptions)) 478fa1a5a38SJayashankar Padath { 479fa1a5a38SJayashankar Padath return; 480fa1a5a38SJayashankar Padath } 481fa1a5a38SJayashankar Padath 482274dfe62SJayashankar Padath if (pushUriOptions) 483274dfe62SJayashankar Padath { 484274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 485274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 486274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 487274dfe62SJayashankar Padath { 488274dfe62SJayashankar Padath return; 489274dfe62SJayashankar Padath } 490274dfe62SJayashankar Padath 491274dfe62SJayashankar Padath if (pushUriApplyTime) 492274dfe62SJayashankar Padath { 493274dfe62SJayashankar Padath std::optional<std::string> applyTime; 494274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 495274dfe62SJayashankar Padath applyTime)) 496274dfe62SJayashankar Padath { 497274dfe62SJayashankar Padath return; 498274dfe62SJayashankar Padath } 499274dfe62SJayashankar Padath 500274dfe62SJayashankar Padath if (applyTime) 501fa1a5a38SJayashankar Padath { 502fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 503fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 504fa1a5a38SJayashankar Padath { 505274dfe62SJayashankar Padath applyTimeNewVal = 506274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 507fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 508fa1a5a38SJayashankar Padath } 509274dfe62SJayashankar Padath else if (applyTime == "OnReset") 510274dfe62SJayashankar Padath { 511274dfe62SJayashankar Padath applyTimeNewVal = 512274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 513274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 514274dfe62SJayashankar Padath } 515fa1a5a38SJayashankar Padath else 516fa1a5a38SJayashankar Padath { 517274dfe62SJayashankar Padath BMCWEB_LOG_INFO 518274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 519274dfe62SJayashankar Padath "acceptable values"; 520274dfe62SJayashankar Padath messages::propertyValueNotInList( 521274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 522274dfe62SJayashankar Padath return; 523fa1a5a38SJayashankar Padath } 524fa1a5a38SJayashankar Padath 525fa1a5a38SJayashankar Padath // Set the requested image apply time value 526fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 527fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 528fa1a5a38SJayashankar Padath if (ec) 529fa1a5a38SJayashankar Padath { 530274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 531274dfe62SJayashankar Padath << ec; 532fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 533fa1a5a38SJayashankar Padath return; 534fa1a5a38SJayashankar Padath } 535fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 536fa1a5a38SJayashankar Padath }, 537fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 538fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 539fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 540274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 541274dfe62SJayashankar Padath "RequestedApplyTime", 542fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 543fa1a5a38SJayashankar Padath } 544274dfe62SJayashankar Padath } 545fa1a5a38SJayashankar Padath } 546fa1a5a38SJayashankar Padath } 547fa1a5a38SJayashankar Padath 548acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 5491abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5501abe55efSEd Tanous { 551acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 552acb7cfb4SJennifer Lee 5530e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 554acb7cfb4SJennifer Lee 55586adcd6dSAndrew Geissler // Setup callback for when new software detected 55686adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 557acb7cfb4SJennifer Lee 558acb7cfb4SJennifer Lee std::string filepath( 559acb7cfb4SJennifer Lee "/tmp/images/" + 560acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 561acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 562acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 563acb7cfb4SJennifer Lee std::ofstream::trunc); 564acb7cfb4SJennifer Lee out << req.body; 565acb7cfb4SJennifer Lee out.close(); 566acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 567acb7cfb4SJennifer Lee } 568729dae72SJennifer Lee }; 569729dae72SJennifer Lee 5701abe55efSEd Tanous class SoftwareInventoryCollection : public Node 5711abe55efSEd Tanous { 572729dae72SJennifer Lee public: 573729dae72SJennifer Lee template <typename CrowApp> 5741abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 5751abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 5761abe55efSEd Tanous { 577729dae72SJennifer Lee entityPrivileges = { 578729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 579729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 580729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 581729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 582729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 583729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 584729dae72SJennifer Lee } 585729dae72SJennifer Lee 586729dae72SJennifer Lee private: 58755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 5881abe55efSEd Tanous const std::vector<std::string> ¶ms) override 5891abe55efSEd Tanous { 590c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 5910f74e643SEd Tanous res.jsonValue["@odata.type"] = 5920f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 5930f74e643SEd Tanous res.jsonValue["@odata.id"] = 5940f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 5950f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 596c711bf86SEd Tanous 597c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 598c711bf86SEd Tanous [asyncResp]( 599c711bf86SEd Tanous const boost::system::error_code ec, 6006c4eb9deSJennifer Lee const std::vector<std::pair< 6011abe55efSEd Tanous std::string, std::vector<std::pair< 6021abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6036c4eb9deSJennifer Lee &subtree) { 6041abe55efSEd Tanous if (ec) 6051abe55efSEd Tanous { 606f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6076c4eb9deSJennifer Lee return; 608729dae72SJennifer Lee } 609c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 610c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 6116c4eb9deSJennifer Lee 6121abe55efSEd Tanous for (auto &obj : subtree) 6131abe55efSEd Tanous { 614f4b65ab1SJennifer Lee // if can't parse fw id then return 61527826b5fSEd Tanous std::size_t idPos; 61627826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 617f4b65ab1SJennifer Lee { 618f12894f8SJason M. Bills messages::internalError(asyncResp->res); 619f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 620f4b65ab1SJennifer Lee return; 621f4b65ab1SJennifer Lee } 622f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 623f4b65ab1SJennifer Lee 624c711bf86SEd Tanous nlohmann::json &members = 625c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 626c711bf86SEd Tanous members.push_back( 627f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 6281abe55efSEd Tanous "FirmwareInventory/" + 629f4b65ab1SJennifer Lee swId}}); 630e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 631c711bf86SEd Tanous members.size(); 6326c4eb9deSJennifer Lee } 633c711bf86SEd Tanous }, 6342830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 6352830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 6362830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 6372830a9cfSAndrew Geissler // path must be used here as input to mapper 638c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 639c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 6402830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6412830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 6421abe55efSEd Tanous std::array<const char *, 1>{ 6431abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 644729dae72SJennifer Lee } 645729dae72SJennifer Lee }; 646c711bf86SEd Tanous 6471abe55efSEd Tanous class SoftwareInventory : public Node 6481abe55efSEd Tanous { 649729dae72SJennifer Lee public: 650729dae72SJennifer Lee template <typename CrowApp> 6511abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 6521abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 6531abe55efSEd Tanous std::string()) 6541abe55efSEd Tanous { 655729dae72SJennifer Lee entityPrivileges = { 656729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 657729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 658729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 659729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 660729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 661729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 662729dae72SJennifer Lee } 663729dae72SJennifer Lee 664729dae72SJennifer Lee private: 66587d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 66687d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 66787d84729SAndrew Geissler const std::string &purpose) 66887d84729SAndrew Geissler { 66987d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 67087d84729SAndrew Geissler { 67187d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 67287d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 67387d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 67487d84729SAndrew Geissler } 67587d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 67687d84729SAndrew Geissler { 677f723d733SGunnar Mills nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 678f723d733SGunnar Mills members.push_back( 679f723d733SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system/Bios"}}); 680f723d733SGunnar Mills aResp->res.jsonValue["Members@odata.count"] = members.size(); 68187d84729SAndrew Geissler } 68287d84729SAndrew Geissler else 68387d84729SAndrew Geissler { 68487d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 68587d84729SAndrew Geissler } 68687d84729SAndrew Geissler } 68787d84729SAndrew Geissler 68855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6891abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6901abe55efSEd Tanous { 691c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6926c4eb9deSJennifer Lee 6931abe55efSEd Tanous if (params.size() != 1) 6941abe55efSEd Tanous { 695f12894f8SJason M. Bills messages::internalError(res); 696729dae72SJennifer Lee res.end(); 697729dae72SJennifer Lee return; 698729dae72SJennifer Lee } 699729dae72SJennifer Lee 7003ae837c9SEd Tanous std::shared_ptr<std::string> swId = 701c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 702c711bf86SEd Tanous 70355c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 7043ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 705c711bf86SEd Tanous 706c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 7073ae837c9SEd Tanous [asyncResp, swId]( 708c711bf86SEd Tanous const boost::system::error_code ec, 7096c4eb9deSJennifer Lee const std::vector<std::pair< 7101abe55efSEd Tanous std::string, std::vector<std::pair< 7111abe55efSEd Tanous std::string, std::vector<std::string>>>>> 7126c4eb9deSJennifer Lee &subtree) { 71355c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 7141abe55efSEd Tanous if (ec) 7151abe55efSEd Tanous { 716f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7176c4eb9deSJennifer Lee return; 7186c4eb9deSJennifer Lee } 7196c4eb9deSJennifer Lee 7206913228dSAndrew Geissler // Ensure we find our input swId, otherwise return an error 7216913228dSAndrew Geissler bool found = false; 7221abe55efSEd Tanous for (const std::pair< 7231abe55efSEd Tanous std::string, 7241abe55efSEd Tanous std::vector< 7251abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 7261abe55efSEd Tanous &obj : subtree) 7271abe55efSEd Tanous { 7283ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 7291abe55efSEd Tanous { 730acb7cfb4SJennifer Lee continue; 731acb7cfb4SJennifer Lee } 732acb7cfb4SJennifer Lee 733f4b65ab1SJennifer Lee if (obj.second.size() < 1) 7341abe55efSEd Tanous { 735acb7cfb4SJennifer Lee continue; 736acb7cfb4SJennifer Lee } 7376c4eb9deSJennifer Lee 7386913228dSAndrew Geissler found = true; 739e0dd8057SAndrew Geissler fw_util::getFwStatus(asyncResp, swId, obj.second[0].first); 740e0dd8057SAndrew Geissler 74155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7421abe55efSEd Tanous [asyncResp, 7433ae837c9SEd Tanous swId](const boost::system::error_code error_code, 7441abe55efSEd Tanous const boost::container::flat_map< 7451abe55efSEd Tanous std::string, VariantType> &propertiesList) { 7461abe55efSEd Tanous if (error_code) 7471abe55efSEd Tanous { 748f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7496c4eb9deSJennifer Lee return; 7506c4eb9deSJennifer Lee } 7511abe55efSEd Tanous boost::container::flat_map< 7521abe55efSEd Tanous std::string, VariantType>::const_iterator it = 7536c4eb9deSJennifer Lee propertiesList.find("Purpose"); 7541abe55efSEd Tanous if (it == propertiesList.end()) 7551abe55efSEd Tanous { 7561abe55efSEd Tanous BMCWEB_LOG_DEBUG 7571abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 758f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 759f12894f8SJason M. Bills "Purpose"); 7606c4eb9deSJennifer Lee return; 7616c4eb9deSJennifer Lee } 7623ae837c9SEd Tanous const std::string *swInvPurpose = 763abf2add6SEd Tanous std::get_if<std::string>(&it->second); 7643ae837c9SEd Tanous if (swInvPurpose == nullptr) 7651abe55efSEd Tanous { 7661abe55efSEd Tanous BMCWEB_LOG_DEBUG 7671abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 768f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 769f12894f8SJason M. Bills "", "Purpose"); 770acb7cfb4SJennifer Lee return; 771acb7cfb4SJennifer Lee } 772c711bf86SEd Tanous 7733ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 7743ae837c9SEd Tanous << *swInvPurpose; 775c711bf86SEd Tanous it = propertiesList.find("Version"); 7761abe55efSEd Tanous if (it == propertiesList.end()) 7771abe55efSEd Tanous { 7781abe55efSEd Tanous BMCWEB_LOG_DEBUG 7791abe55efSEd Tanous << "Can't find property \"Version\"!"; 780f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 781f12894f8SJason M. Bills "Version"); 782c711bf86SEd Tanous return; 783acb7cfb4SJennifer Lee } 784acb7cfb4SJennifer Lee 785f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 786c711bf86SEd Tanous 787f4b65ab1SJennifer Lee const std::string *version = 788abf2add6SEd Tanous std::get_if<std::string>(&it->second); 789f4b65ab1SJennifer Lee 790f4b65ab1SJennifer Lee if (version == nullptr) 7911abe55efSEd Tanous { 7921abe55efSEd Tanous BMCWEB_LOG_DEBUG 7931abe55efSEd Tanous << "Can't find property \"Version\"!"; 794f12894f8SJason M. Bills 795f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 796f12894f8SJason M. Bills "", "Version"); 7976c4eb9deSJennifer Lee return; 7986c4eb9deSJennifer Lee } 799c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 8003ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 80154daabe7SAndrew Geissler 80254daabe7SAndrew Geissler // swInvPurpose is of format: 80354daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 804e2e96770SJames Feist // Translate this to "ABC image" 80554daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 80654daabe7SAndrew Geissler if (endDesc == std::string::npos) 80754daabe7SAndrew Geissler { 80854daabe7SAndrew Geissler messages::internalError(asyncResp->res); 80954daabe7SAndrew Geissler return; 81054daabe7SAndrew Geissler } 81154daabe7SAndrew Geissler endDesc++; 81254daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 81354daabe7SAndrew Geissler { 81454daabe7SAndrew Geissler messages::internalError(asyncResp->res); 81554daabe7SAndrew Geissler return; 81654daabe7SAndrew Geissler } 81754daabe7SAndrew Geissler 81854daabe7SAndrew Geissler std::string formatDesc = 81954daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 82054daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 821e2e96770SJames Feist formatDesc + " image"; 82287d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 8236c4eb9deSJennifer Lee }, 824c711bf86SEd Tanous obj.second[0].first, obj.first, 825c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 826c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 8276c4eb9deSJennifer Lee } 8286913228dSAndrew Geissler if (!found) 8296913228dSAndrew Geissler { 8306913228dSAndrew Geissler BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!"; 8316913228dSAndrew Geissler messages::resourceMissingAtURI( 8326913228dSAndrew Geissler asyncResp->res, 8336913228dSAndrew Geissler "/redfish/v1/UpdateService/FirmwareInventory/" + *swId); 8346913228dSAndrew Geissler return; 8356913228dSAndrew Geissler } 8364e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.type"] = 8374e68c45bSAyushi Smriti "#SoftwareInventory.v1_1_0.SoftwareInventory"; 8384e68c45bSAyushi Smriti asyncResp->res.jsonValue["Name"] = "Software Inventory"; 8394e68c45bSAyushi Smriti asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK"; 8403f8a743aSAppaRao Puli 8413f8a743aSAppaRao Puli asyncResp->res.jsonValue["Updateable"] = false; 8423f8a743aSAppaRao Puli fw_util::getFwUpdateableStatus(asyncResp, swId); 843c711bf86SEd Tanous }, 844c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 845c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 846271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 847271584abSEd Tanous static_cast<int32_t>(0), 8481abe55efSEd Tanous std::array<const char *, 1>{ 8491abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 8506c4eb9deSJennifer Lee } 851729dae72SJennifer Lee }; 852729dae72SJennifer Lee 853729dae72SJennifer Lee } // namespace redfish 854