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, 61fe306728SJames Feist sdbusplus::message::message &m, 62fe306728SJames Feist const crow::Request &req) 6386adcd6dSAndrew Geissler { 6486adcd6dSAndrew Geissler std::vector<std::pair< 6586adcd6dSAndrew Geissler std::string, 6686adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6786adcd6dSAndrew Geissler interfacesProperties; 6886adcd6dSAndrew Geissler 6986adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 7086adcd6dSAndrew Geissler 7186adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 7286adcd6dSAndrew Geissler 7386adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7486adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 7586adcd6dSAndrew Geissler { 7686adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7786adcd6dSAndrew Geissler 7886adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 7986adcd6dSAndrew Geissler { 8086adcd6dSAndrew Geissler // Found our interface, disable callbacks 8186adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 8286adcd6dSAndrew Geissler 8386adcd6dSAndrew Geissler // Retrieve service and activate 8486adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 85fe306728SJames Feist [objPath, asyncResp, 86fe306728SJames Feist req](const boost::system::error_code error_code, 8786adcd6dSAndrew Geissler const std::vector<std::pair< 8886adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 8986adcd6dSAndrew Geissler if (error_code) 9086adcd6dSAndrew Geissler { 9186adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 9286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 9386adcd6dSAndrew Geissler << error_code.message(); 940554c984SAndrew Geissler if (asyncResp) 950554c984SAndrew Geissler { 9686adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 970554c984SAndrew Geissler } 9886adcd6dSAndrew Geissler cleanUp(); 9986adcd6dSAndrew Geissler return; 10086adcd6dSAndrew Geissler } 10186adcd6dSAndrew Geissler // Ensure we only got one service back 10286adcd6dSAndrew Geissler if (objInfo.size() != 1) 10386adcd6dSAndrew Geissler { 10486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 10586adcd6dSAndrew Geissler << objInfo.size(); 1060554c984SAndrew Geissler if (asyncResp) 1070554c984SAndrew Geissler { 10886adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 1090554c984SAndrew Geissler } 11086adcd6dSAndrew Geissler cleanUp(); 11186adcd6dSAndrew Geissler return; 11286adcd6dSAndrew Geissler } 11386adcd6dSAndrew Geissler // cancel timer only when 11486adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 11586adcd6dSAndrew Geissler // is added 11686adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 11786adcd6dSAndrew Geissler 11886adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 1190554c984SAndrew Geissler if (asyncResp) 1200554c984SAndrew Geissler { 12132898ceaSJames Feist std::shared_ptr<task::TaskData> task = 12232898ceaSJames Feist task::TaskData::createTask( 12332898ceaSJames Feist [](boost::system::error_code ec, 12432898ceaSJames Feist sdbusplus::message::message &msg, 12532898ceaSJames Feist const std::shared_ptr<task::TaskData> 12632898ceaSJames Feist &taskData) { 12732898ceaSJames Feist if (ec) 12832898ceaSJames Feist { 12932898ceaSJames Feist return task::completed; 13032898ceaSJames Feist } 13132898ceaSJames Feist 13232898ceaSJames Feist std::string iface; 13332898ceaSJames Feist boost::container::flat_map< 134*fd9ab9e1SJames Feist std::string, 135*fd9ab9e1SJames Feist std::variant<std::string, uint8_t>> 13632898ceaSJames Feist values; 137*fd9ab9e1SJames Feist 138*fd9ab9e1SJames Feist std::string index = 139*fd9ab9e1SJames Feist std::to_string(taskData->index); 14032898ceaSJames Feist msg.read(iface, values); 141*fd9ab9e1SJames Feist 142*fd9ab9e1SJames Feist if (iface == "xyz.openbmc_project.Software." 143*fd9ab9e1SJames Feist "Activation") 144*fd9ab9e1SJames Feist { 14532898ceaSJames Feist auto findActivation = 14632898ceaSJames Feist values.find("Activation"); 14732898ceaSJames Feist if (findActivation == values.end()) 14832898ceaSJames Feist { 14932898ceaSJames Feist return !task::completed; 15032898ceaSJames Feist } 15132898ceaSJames Feist std::string *state = 15232898ceaSJames Feist std::get_if<std::string>( 15332898ceaSJames Feist &(findActivation->second)); 15432898ceaSJames Feist 15532898ceaSJames Feist if (state == nullptr) 15632898ceaSJames Feist { 15732898ceaSJames Feist taskData->messages.emplace_back( 15832898ceaSJames Feist messages::internalError()); 15932898ceaSJames Feist return task::completed; 16032898ceaSJames Feist } 16132898ceaSJames Feist 162*fd9ab9e1SJames Feist if (boost::ends_with(*state, 163*fd9ab9e1SJames Feist "Invalid") || 16432898ceaSJames Feist boost::ends_with(*state, "Failed")) 16532898ceaSJames Feist { 16632898ceaSJames Feist taskData->state = "Exception"; 16732898ceaSJames Feist taskData->status = "Warning"; 16832898ceaSJames Feist taskData->messages.emplace_back( 169e5d5006bSJames Feist messages::taskAborted(index)); 17032898ceaSJames Feist return task::completed; 17132898ceaSJames Feist } 17232898ceaSJames Feist 17332898ceaSJames Feist if (boost::ends_with(*state, "Staged")) 17432898ceaSJames Feist { 175*fd9ab9e1SJames Feist taskData->state = "Stopping"; 176*fd9ab9e1SJames Feist taskData->messages.emplace_back( 177*fd9ab9e1SJames Feist messages::taskPaused(index)); 178*fd9ab9e1SJames Feist 179*fd9ab9e1SJames Feist // its staged, set a long timer to 180*fd9ab9e1SJames Feist // allow them time to complete the 181*fd9ab9e1SJames Feist // update (probably cycle the 182*fd9ab9e1SJames Feist // system) if this expires then 183*fd9ab9e1SJames Feist // task will be cancelled 184*fd9ab9e1SJames Feist taskData->extendTimer( 185*fd9ab9e1SJames Feist std::chrono::hours(5)); 18632898ceaSJames Feist return !task::completed; 18732898ceaSJames Feist } 18832898ceaSJames Feist 18932898ceaSJames Feist if (boost::ends_with(*state, "Active")) 19032898ceaSJames Feist { 19132898ceaSJames Feist taskData->messages.emplace_back( 192*fd9ab9e1SJames Feist messages::taskCompletedOK( 193*fd9ab9e1SJames Feist index)); 19432898ceaSJames Feist taskData->state = "Completed"; 19532898ceaSJames Feist return task::completed; 19632898ceaSJames Feist } 197*fd9ab9e1SJames Feist } 198*fd9ab9e1SJames Feist else if (iface == 199*fd9ab9e1SJames Feist "xyz.openbmc_project.Software." 200*fd9ab9e1SJames Feist "ActivationProgress") 201*fd9ab9e1SJames Feist { 202*fd9ab9e1SJames Feist auto findProgress = 203*fd9ab9e1SJames Feist values.find("Progress"); 204*fd9ab9e1SJames Feist if (findProgress == values.end()) 205*fd9ab9e1SJames Feist { 206*fd9ab9e1SJames Feist return !task::completed; 207*fd9ab9e1SJames Feist } 208*fd9ab9e1SJames Feist uint8_t *progress = 209*fd9ab9e1SJames Feist std::get_if<uint8_t>( 210*fd9ab9e1SJames Feist &(findProgress->second)); 211*fd9ab9e1SJames Feist 212*fd9ab9e1SJames Feist if (progress == nullptr) 213*fd9ab9e1SJames Feist { 214*fd9ab9e1SJames Feist taskData->messages.emplace_back( 215*fd9ab9e1SJames Feist messages::internalError()); 216*fd9ab9e1SJames Feist return task::completed; 217*fd9ab9e1SJames Feist } 218*fd9ab9e1SJames Feist taskData->messages.emplace_back( 219*fd9ab9e1SJames Feist messages::taskProgressChanged( 220*fd9ab9e1SJames Feist index, static_cast<size_t>( 221*fd9ab9e1SJames Feist *progress))); 222*fd9ab9e1SJames Feist 223*fd9ab9e1SJames Feist // if we're getting status updates it's 224*fd9ab9e1SJames Feist // still alive, update timer 225*fd9ab9e1SJames Feist taskData->extendTimer( 226*fd9ab9e1SJames Feist std::chrono::minutes(5)); 227*fd9ab9e1SJames Feist } 22832898ceaSJames Feist 22932898ceaSJames Feist // as firmware update often results in a 23032898ceaSJames Feist // reboot, the task may never "complete" 23132898ceaSJames Feist // unless it is an error 23232898ceaSJames Feist 23332898ceaSJames Feist return !task::completed; 23432898ceaSJames Feist }, 23532898ceaSJames Feist "type='signal',interface='org.freedesktop.DBus." 23632898ceaSJames Feist "Properties'," 237*fd9ab9e1SJames Feist "member='PropertiesChanged',path='" + 23832898ceaSJames Feist objPath.str + "'"); 23932898ceaSJames Feist task->startTimer(std::chrono::minutes(5)); 24032898ceaSJames Feist task->populateResp(asyncResp->res); 241fe306728SJames Feist task->payload.emplace(req); 2420554c984SAndrew Geissler } 24386adcd6dSAndrew Geissler fwUpdateInProgress = false; 24486adcd6dSAndrew Geissler }, 24586adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 24686adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 24786adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 24886adcd6dSAndrew Geissler std::array<const char *, 1>{ 24986adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 25086adcd6dSAndrew Geissler } 25186adcd6dSAndrew Geissler } 25286adcd6dSAndrew Geissler } 25386adcd6dSAndrew Geissler 2540554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 2550554c984SAndrew Geissler // then no asyncResp updates will occur 25686adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 2570554c984SAndrew Geissler const crow::Request &req, 2580554c984SAndrew Geissler int timeoutTimeSeconds = 5) 25986adcd6dSAndrew Geissler { 26086adcd6dSAndrew Geissler // Only allow one FW update at a time 26186adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 26286adcd6dSAndrew Geissler { 2630554c984SAndrew Geissler if (asyncResp) 2640554c984SAndrew Geissler { 26586adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 2660554c984SAndrew Geissler } 26786adcd6dSAndrew Geissler return; 26886adcd6dSAndrew Geissler } 26986adcd6dSAndrew Geissler 2700554c984SAndrew Geissler fwAvailableTimer = 271271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 27286adcd6dSAndrew Geissler 273271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 27486adcd6dSAndrew Geissler 27586adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 27686adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 27786adcd6dSAndrew Geissler cleanUp(); 27886adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 27986adcd6dSAndrew Geissler { 28086adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 28186adcd6dSAndrew Geissler return; 28286adcd6dSAndrew Geissler } 28386adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 28486adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 28586adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 28686adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 28786adcd6dSAndrew Geissler if (ec) 28886adcd6dSAndrew Geissler { 28986adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 29086adcd6dSAndrew Geissler return; 29186adcd6dSAndrew Geissler } 2920554c984SAndrew Geissler if (asyncResp) 2930554c984SAndrew Geissler { 29486adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 2950554c984SAndrew Geissler } 29686adcd6dSAndrew Geissler }); 29786adcd6dSAndrew Geissler 298fe306728SJames Feist auto callback = [asyncResp, req](sdbusplus::message::message &m) { 29986adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 300fe306728SJames Feist softwareInterfaceAdded(asyncResp, m, req); 30186adcd6dSAndrew Geissler }; 30286adcd6dSAndrew Geissler 30386adcd6dSAndrew Geissler fwUpdateInProgress = true; 30486adcd6dSAndrew Geissler 30586adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 30686adcd6dSAndrew Geissler *crow::connections::systemBus, 30786adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 30886adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 30986adcd6dSAndrew Geissler callback); 31086adcd6dSAndrew Geissler } 311729dae72SJennifer Lee 3120554c984SAndrew Geissler /** 3130554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 3140554c984SAndrew Geissler * SimpleUpdate action. 3150554c984SAndrew Geissler */ 3160554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 3170554c984SAndrew Geissler { 3180554c984SAndrew Geissler public: 3190554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 3200554c984SAndrew Geissler Node(app, 3210554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 3220554c984SAndrew Geissler { 3230554c984SAndrew Geissler entityPrivileges = { 3240554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 3250554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 3260554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 3270554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 3280554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 3290554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 3300554c984SAndrew Geissler } 3310554c984SAndrew Geissler 3320554c984SAndrew Geissler private: 3330554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 3340554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 3350554c984SAndrew Geissler { 3360554c984SAndrew Geissler std::optional<std::string> transferProtocol; 3370554c984SAndrew Geissler std::string imageURI; 3380554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 3390554c984SAndrew Geissler 3400554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 3410554c984SAndrew Geissler 3420554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 3430554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 3440554c984SAndrew Geissler // within it. 3450554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 3460554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 3470554c984SAndrew Geissler 3480554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 3490554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 3500554c984SAndrew Geissler { 3510554c984SAndrew Geissler BMCWEB_LOG_DEBUG 3520554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 3530554c984SAndrew Geissler return; 3540554c984SAndrew Geissler } 3550554c984SAndrew Geissler if (!transferProtocol) 3560554c984SAndrew Geissler { 3570554c984SAndrew Geissler // Must be option 2 3580554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 3590554c984SAndrew Geissler size_t separator = imageURI.find(":"); 3600554c984SAndrew Geissler if ((separator == std::string::npos) || 3610554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3620554c984SAndrew Geissler { 3630554c984SAndrew Geissler messages::actionParameterValueTypeError( 3640554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3650554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3660554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 3670554c984SAndrew Geissler << imageURI; 3680554c984SAndrew Geissler return; 3690554c984SAndrew Geissler } 3700554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 3710554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 3720554c984SAndrew Geissler boost::to_upper(*transferProtocol); 3730554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 3740554c984SAndrew Geissler << *transferProtocol; 3750554c984SAndrew Geissler 3760554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 3770554c984SAndrew Geissler // below 3780554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 3790554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 3800554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 3810554c984SAndrew Geissler } 3820554c984SAndrew Geissler 3830554c984SAndrew Geissler // OpenBMC currently only supports TFTP 3840554c984SAndrew Geissler if (*transferProtocol != "TFTP") 3850554c984SAndrew Geissler { 3860554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 3870554c984SAndrew Geissler "TransferProtocol", 3880554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3890554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 3900554c984SAndrew Geissler << *transferProtocol; 3910554c984SAndrew Geissler return; 3920554c984SAndrew Geissler } 3930554c984SAndrew Geissler 3940554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 3950554c984SAndrew Geissler size_t separator = imageURI.find("/"); 3960554c984SAndrew Geissler if ((separator == std::string::npos) || 3970554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3980554c984SAndrew Geissler { 3990554c984SAndrew Geissler messages::actionParameterValueTypeError( 4000554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 4010554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 4020554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 4030554c984SAndrew Geissler return; 4040554c984SAndrew Geissler } 4050554c984SAndrew Geissler 4060554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 4070554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 4080554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 4090554c984SAndrew Geissler 4100554c984SAndrew Geissler // Setup callback for when new software detected 4110554c984SAndrew Geissler // Give TFTP 2 minutes to complete 4120554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 4130554c984SAndrew Geissler 4140554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 4150554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 4160554c984SAndrew Geissler // has been started. The callback above will ensure the activate 4170554c984SAndrew Geissler // is started once the download has completed 4180554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 4190554c984SAndrew Geissler 4200554c984SAndrew Geissler // Call TFTP service 4210554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 4220554c984SAndrew Geissler [](const boost::system::error_code ec) { 4230554c984SAndrew Geissler if (ec) 4240554c984SAndrew Geissler { 4250554c984SAndrew Geissler // messages::internalError(asyncResp->res); 4260554c984SAndrew Geissler cleanUp(); 4270554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 4280554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 4290554c984SAndrew Geissler } 4300554c984SAndrew Geissler else 4310554c984SAndrew Geissler { 4320554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 4330554c984SAndrew Geissler } 4340554c984SAndrew Geissler }, 4350554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 4360554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 4370554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 4380554c984SAndrew Geissler 4390554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 4400554c984SAndrew Geissler } 4410554c984SAndrew Geissler }; 4420554c984SAndrew Geissler 4431abe55efSEd Tanous class UpdateService : public Node 4441abe55efSEd Tanous { 445729dae72SJennifer Lee public: 4461abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 4471abe55efSEd Tanous { 448729dae72SJennifer Lee entityPrivileges = { 449729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 450729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 451729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 452729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 453729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 454729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 455729dae72SJennifer Lee } 456729dae72SJennifer Lee 457729dae72SJennifer Lee private: 45855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 4591abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4601abe55efSEd Tanous { 461274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 462274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 4630f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 4640f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 4650f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 4660f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 4670f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 4680f74e643SEd Tanous // UpdateService cannot be disabled 4690f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 4700f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 4710f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 4720554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 4730554c984SAndrew Geissler // Update Actions object. 4740554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 4750554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 4760554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 4770554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 4780554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 4790554c984SAndrew Geissler "TFTP"}; 4800554c984SAndrew Geissler #endif 481274dfe62SJayashankar Padath // Get the current ApplyTime value 482274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 483274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 484274dfe62SJayashankar Padath const std::variant<std::string> &applyTime) { 485274dfe62SJayashankar Padath if (ec) 486274dfe62SJayashankar Padath { 487274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 488274dfe62SJayashankar Padath messages::internalError(aResp->res); 489274dfe62SJayashankar Padath return; 490274dfe62SJayashankar Padath } 491274dfe62SJayashankar Padath 492274dfe62SJayashankar Padath const std::string *s = std::get_if<std::string>(&applyTime); 493274dfe62SJayashankar Padath if (s == nullptr) 494274dfe62SJayashankar Padath { 495274dfe62SJayashankar Padath return; 496274dfe62SJayashankar Padath } 497274dfe62SJayashankar Padath // Store the ApplyTime Value 498274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 499274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 500274dfe62SJayashankar Padath { 501274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 502274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 503274dfe62SJayashankar Padath "Immediate"; 504274dfe62SJayashankar Padath } 505274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 506274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 507274dfe62SJayashankar Padath { 508274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 509274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 510274dfe62SJayashankar Padath "OnReset"; 511274dfe62SJayashankar Padath } 512274dfe62SJayashankar Padath }, 513274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 514274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 515274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 516274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 517729dae72SJennifer Lee } 5180e7de46fSAndrew Geissler 519fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 520fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 521fa1a5a38SJayashankar Padath { 522fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 523fa1a5a38SJayashankar Padath 524fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 525fa1a5a38SJayashankar Padath 526274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 527274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 528274dfe62SJayashankar Padath pushUriOptions)) 529fa1a5a38SJayashankar Padath { 530fa1a5a38SJayashankar Padath return; 531fa1a5a38SJayashankar Padath } 532fa1a5a38SJayashankar Padath 533274dfe62SJayashankar Padath if (pushUriOptions) 534274dfe62SJayashankar Padath { 535274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 536274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 537274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 538274dfe62SJayashankar Padath { 539274dfe62SJayashankar Padath return; 540274dfe62SJayashankar Padath } 541274dfe62SJayashankar Padath 542274dfe62SJayashankar Padath if (pushUriApplyTime) 543274dfe62SJayashankar Padath { 544274dfe62SJayashankar Padath std::optional<std::string> applyTime; 545274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 546274dfe62SJayashankar Padath applyTime)) 547274dfe62SJayashankar Padath { 548274dfe62SJayashankar Padath return; 549274dfe62SJayashankar Padath } 550274dfe62SJayashankar Padath 551274dfe62SJayashankar Padath if (applyTime) 552fa1a5a38SJayashankar Padath { 553fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 554fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 555fa1a5a38SJayashankar Padath { 556274dfe62SJayashankar Padath applyTimeNewVal = 557274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 558fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 559fa1a5a38SJayashankar Padath } 560274dfe62SJayashankar Padath else if (applyTime == "OnReset") 561274dfe62SJayashankar Padath { 562274dfe62SJayashankar Padath applyTimeNewVal = 563274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 564274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 565274dfe62SJayashankar Padath } 566fa1a5a38SJayashankar Padath else 567fa1a5a38SJayashankar Padath { 568274dfe62SJayashankar Padath BMCWEB_LOG_INFO 569274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 570274dfe62SJayashankar Padath "acceptable values"; 571274dfe62SJayashankar Padath messages::propertyValueNotInList( 572274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 573274dfe62SJayashankar Padath return; 574fa1a5a38SJayashankar Padath } 575fa1a5a38SJayashankar Padath 576fa1a5a38SJayashankar Padath // Set the requested image apply time value 577fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 578fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 579fa1a5a38SJayashankar Padath if (ec) 580fa1a5a38SJayashankar Padath { 581274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 582274dfe62SJayashankar Padath << ec; 583fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 584fa1a5a38SJayashankar Padath return; 585fa1a5a38SJayashankar Padath } 586fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 587fa1a5a38SJayashankar Padath }, 588fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 589fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 590fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 591274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 592274dfe62SJayashankar Padath "RequestedApplyTime", 593fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 594fa1a5a38SJayashankar Padath } 595274dfe62SJayashankar Padath } 596fa1a5a38SJayashankar Padath } 597fa1a5a38SJayashankar Padath } 598fa1a5a38SJayashankar Padath 599acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 6001abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6011abe55efSEd Tanous { 602acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 603acb7cfb4SJennifer Lee 6040e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 605acb7cfb4SJennifer Lee 60686adcd6dSAndrew Geissler // Setup callback for when new software detected 60786adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 608acb7cfb4SJennifer Lee 609acb7cfb4SJennifer Lee std::string filepath( 610acb7cfb4SJennifer Lee "/tmp/images/" + 611acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 612acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 613acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 614acb7cfb4SJennifer Lee std::ofstream::trunc); 615acb7cfb4SJennifer Lee out << req.body; 616acb7cfb4SJennifer Lee out.close(); 617acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 618acb7cfb4SJennifer Lee } 619729dae72SJennifer Lee }; 620729dae72SJennifer Lee 6211abe55efSEd Tanous class SoftwareInventoryCollection : public Node 6221abe55efSEd Tanous { 623729dae72SJennifer Lee public: 624729dae72SJennifer Lee template <typename CrowApp> 6251abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 6261abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 6271abe55efSEd Tanous { 628729dae72SJennifer Lee entityPrivileges = { 629729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 630729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 631729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 632729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 633729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 634729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 635729dae72SJennifer Lee } 636729dae72SJennifer Lee 637729dae72SJennifer Lee private: 63855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6391abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6401abe55efSEd Tanous { 641c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6420f74e643SEd Tanous res.jsonValue["@odata.type"] = 6430f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 6440f74e643SEd Tanous res.jsonValue["@odata.id"] = 6450f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 6460f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 647c711bf86SEd Tanous 648c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 649c711bf86SEd Tanous [asyncResp]( 650c711bf86SEd Tanous const boost::system::error_code ec, 6516c4eb9deSJennifer Lee const std::vector<std::pair< 6521abe55efSEd Tanous std::string, std::vector<std::pair< 6531abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6546c4eb9deSJennifer Lee &subtree) { 6551abe55efSEd Tanous if (ec) 6561abe55efSEd Tanous { 657f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6586c4eb9deSJennifer Lee return; 659729dae72SJennifer Lee } 660c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 661c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 6626c4eb9deSJennifer Lee 6631abe55efSEd Tanous for (auto &obj : subtree) 6641abe55efSEd Tanous { 665f4b65ab1SJennifer Lee // if can't parse fw id then return 66627826b5fSEd Tanous std::size_t idPos; 66727826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 668f4b65ab1SJennifer Lee { 669f12894f8SJason M. Bills messages::internalError(asyncResp->res); 670f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 671f4b65ab1SJennifer Lee return; 672f4b65ab1SJennifer Lee } 673f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 674f4b65ab1SJennifer Lee 675c711bf86SEd Tanous nlohmann::json &members = 676c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 677c711bf86SEd Tanous members.push_back( 678f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 6791abe55efSEd Tanous "FirmwareInventory/" + 680f4b65ab1SJennifer Lee swId}}); 681e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 682c711bf86SEd Tanous members.size(); 6836c4eb9deSJennifer Lee } 684c711bf86SEd Tanous }, 6852830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 6862830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 6872830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 6882830a9cfSAndrew Geissler // path must be used here as input to mapper 689c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 690c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 6912830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6922830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 6931abe55efSEd Tanous std::array<const char *, 1>{ 6941abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 695729dae72SJennifer Lee } 696729dae72SJennifer Lee }; 697c711bf86SEd Tanous 6981abe55efSEd Tanous class SoftwareInventory : public Node 6991abe55efSEd Tanous { 700729dae72SJennifer Lee public: 701729dae72SJennifer Lee template <typename CrowApp> 7021abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 7031abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 7041abe55efSEd Tanous std::string()) 7051abe55efSEd Tanous { 706729dae72SJennifer Lee entityPrivileges = { 707729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 708729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 709729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 710729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 711729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 712729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 713729dae72SJennifer Lee } 714729dae72SJennifer Lee 715729dae72SJennifer Lee private: 71687d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 71787d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 71887d84729SAndrew Geissler const std::string &purpose) 71987d84729SAndrew Geissler { 72087d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 72187d84729SAndrew Geissler { 72287d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 72387d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 72487d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 72587d84729SAndrew Geissler } 72687d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 72787d84729SAndrew Geissler { 728f723d733SGunnar Mills nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 729f723d733SGunnar Mills members.push_back( 730f723d733SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system/Bios"}}); 731f723d733SGunnar Mills aResp->res.jsonValue["Members@odata.count"] = members.size(); 73287d84729SAndrew Geissler } 73387d84729SAndrew Geissler else 73487d84729SAndrew Geissler { 73587d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 73687d84729SAndrew Geissler } 73787d84729SAndrew Geissler } 73887d84729SAndrew Geissler 73955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 7401abe55efSEd Tanous const std::vector<std::string> ¶ms) override 7411abe55efSEd Tanous { 742c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 7436c4eb9deSJennifer Lee 7441abe55efSEd Tanous if (params.size() != 1) 7451abe55efSEd Tanous { 746f12894f8SJason M. Bills messages::internalError(res); 747729dae72SJennifer Lee res.end(); 748729dae72SJennifer Lee return; 749729dae72SJennifer Lee } 750729dae72SJennifer Lee 7513ae837c9SEd Tanous std::shared_ptr<std::string> swId = 752c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 753c711bf86SEd Tanous 75455c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 7553ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 756c711bf86SEd Tanous 757c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 7583ae837c9SEd Tanous [asyncResp, swId]( 759c711bf86SEd Tanous const boost::system::error_code ec, 7606c4eb9deSJennifer Lee const std::vector<std::pair< 7611abe55efSEd Tanous std::string, std::vector<std::pair< 7621abe55efSEd Tanous std::string, std::vector<std::string>>>>> 7636c4eb9deSJennifer Lee &subtree) { 76455c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 7651abe55efSEd Tanous if (ec) 7661abe55efSEd Tanous { 767f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7686c4eb9deSJennifer Lee return; 7696c4eb9deSJennifer Lee } 7706c4eb9deSJennifer Lee 7716913228dSAndrew Geissler // Ensure we find our input swId, otherwise return an error 7726913228dSAndrew Geissler bool found = false; 7731abe55efSEd Tanous for (const std::pair< 7741abe55efSEd Tanous std::string, 7751abe55efSEd Tanous std::vector< 7761abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 7771abe55efSEd Tanous &obj : subtree) 7781abe55efSEd Tanous { 7793ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 7801abe55efSEd Tanous { 781acb7cfb4SJennifer Lee continue; 782acb7cfb4SJennifer Lee } 783acb7cfb4SJennifer Lee 784f4b65ab1SJennifer Lee if (obj.second.size() < 1) 7851abe55efSEd Tanous { 786acb7cfb4SJennifer Lee continue; 787acb7cfb4SJennifer Lee } 7886c4eb9deSJennifer Lee 7896913228dSAndrew Geissler found = true; 790e0dd8057SAndrew Geissler fw_util::getFwStatus(asyncResp, swId, obj.second[0].first); 791e0dd8057SAndrew Geissler 79255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 7931abe55efSEd Tanous [asyncResp, 7943ae837c9SEd Tanous swId](const boost::system::error_code error_code, 7951abe55efSEd Tanous const boost::container::flat_map< 7961abe55efSEd Tanous std::string, VariantType> &propertiesList) { 7971abe55efSEd Tanous if (error_code) 7981abe55efSEd Tanous { 799f12894f8SJason M. Bills messages::internalError(asyncResp->res); 8006c4eb9deSJennifer Lee return; 8016c4eb9deSJennifer Lee } 8021abe55efSEd Tanous boost::container::flat_map< 8031abe55efSEd Tanous std::string, VariantType>::const_iterator it = 8046c4eb9deSJennifer Lee propertiesList.find("Purpose"); 8051abe55efSEd Tanous if (it == propertiesList.end()) 8061abe55efSEd Tanous { 8071abe55efSEd Tanous BMCWEB_LOG_DEBUG 8081abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 809f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 810f12894f8SJason M. Bills "Purpose"); 8116c4eb9deSJennifer Lee return; 8126c4eb9deSJennifer Lee } 8133ae837c9SEd Tanous const std::string *swInvPurpose = 814abf2add6SEd Tanous std::get_if<std::string>(&it->second); 8153ae837c9SEd Tanous if (swInvPurpose == nullptr) 8161abe55efSEd Tanous { 8171abe55efSEd Tanous BMCWEB_LOG_DEBUG 8181abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 819f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 820f12894f8SJason M. Bills "", "Purpose"); 821acb7cfb4SJennifer Lee return; 822acb7cfb4SJennifer Lee } 823c711bf86SEd Tanous 8243ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 8253ae837c9SEd Tanous << *swInvPurpose; 826c711bf86SEd Tanous it = propertiesList.find("Version"); 8271abe55efSEd Tanous if (it == propertiesList.end()) 8281abe55efSEd Tanous { 8291abe55efSEd Tanous BMCWEB_LOG_DEBUG 8301abe55efSEd Tanous << "Can't find property \"Version\"!"; 831f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 832f12894f8SJason M. Bills "Version"); 833c711bf86SEd Tanous return; 834acb7cfb4SJennifer Lee } 835acb7cfb4SJennifer Lee 836f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 837c711bf86SEd Tanous 838f4b65ab1SJennifer Lee const std::string *version = 839abf2add6SEd Tanous std::get_if<std::string>(&it->second); 840f4b65ab1SJennifer Lee 841f4b65ab1SJennifer Lee if (version == nullptr) 8421abe55efSEd Tanous { 8431abe55efSEd Tanous BMCWEB_LOG_DEBUG 8441abe55efSEd Tanous << "Can't find property \"Version\"!"; 845f12894f8SJason M. Bills 846f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 847f12894f8SJason M. Bills "", "Version"); 8486c4eb9deSJennifer Lee return; 8496c4eb9deSJennifer Lee } 850c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 8513ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 85254daabe7SAndrew Geissler 85354daabe7SAndrew Geissler // swInvPurpose is of format: 85454daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 855e2e96770SJames Feist // Translate this to "ABC image" 85654daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 85754daabe7SAndrew Geissler if (endDesc == std::string::npos) 85854daabe7SAndrew Geissler { 85954daabe7SAndrew Geissler messages::internalError(asyncResp->res); 86054daabe7SAndrew Geissler return; 86154daabe7SAndrew Geissler } 86254daabe7SAndrew Geissler endDesc++; 86354daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 86454daabe7SAndrew Geissler { 86554daabe7SAndrew Geissler messages::internalError(asyncResp->res); 86654daabe7SAndrew Geissler return; 86754daabe7SAndrew Geissler } 86854daabe7SAndrew Geissler 86954daabe7SAndrew Geissler std::string formatDesc = 87054daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 87154daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 872e2e96770SJames Feist formatDesc + " image"; 87387d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 8746c4eb9deSJennifer Lee }, 875c711bf86SEd Tanous obj.second[0].first, obj.first, 876c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 877c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 8786c4eb9deSJennifer Lee } 8796913228dSAndrew Geissler if (!found) 8806913228dSAndrew Geissler { 8816913228dSAndrew Geissler BMCWEB_LOG_ERROR << "Input swID " + *swId + " not found!"; 8826913228dSAndrew Geissler messages::resourceMissingAtURI( 8836913228dSAndrew Geissler asyncResp->res, 8846913228dSAndrew Geissler "/redfish/v1/UpdateService/FirmwareInventory/" + *swId); 8856913228dSAndrew Geissler return; 8866913228dSAndrew Geissler } 8874e68c45bSAyushi Smriti asyncResp->res.jsonValue["@odata.type"] = 8884e68c45bSAyushi Smriti "#SoftwareInventory.v1_1_0.SoftwareInventory"; 8894e68c45bSAyushi Smriti asyncResp->res.jsonValue["Name"] = "Software Inventory"; 8904e68c45bSAyushi Smriti asyncResp->res.jsonValue["Status"]["HealthRollup"] = "OK"; 8913f8a743aSAppaRao Puli 8923f8a743aSAppaRao Puli asyncResp->res.jsonValue["Updateable"] = false; 8933f8a743aSAppaRao Puli fw_util::getFwUpdateableStatus(asyncResp, swId); 894c711bf86SEd Tanous }, 895c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 896c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 897271584abSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 898271584abSEd Tanous static_cast<int32_t>(0), 8991abe55efSEd Tanous std::array<const char *, 1>{ 9001abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 9016c4eb9deSJennifer Lee } 902729dae72SJennifer Lee }; 903729dae72SJennifer Lee 904729dae72SJennifer Lee } // namespace redfish 905