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> 22*1214b7e7SGunnar Mills 23abf2add6SEd Tanous #include <variant> 24729dae72SJennifer Lee 251abe55efSEd Tanous namespace redfish 261abe55efSEd Tanous { 2727826b5fSEd Tanous 280e7de46fSAndrew Geissler // Match signals added on software path 29acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; 300e7de46fSAndrew Geissler // Only allow one update at a time 310e7de46fSAndrew Geissler static bool fwUpdateInProgress = false; 3286adcd6dSAndrew Geissler // Timer for software available 33271584abSEd Tanous static std::unique_ptr<boost::asio::steady_timer> fwAvailableTimer; 3486adcd6dSAndrew Geissler 3586adcd6dSAndrew Geissler static void cleanUp() 3686adcd6dSAndrew Geissler { 3786adcd6dSAndrew Geissler fwUpdateInProgress = false; 3886adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 3986adcd6dSAndrew Geissler } 4086adcd6dSAndrew Geissler static void activateImage(const std::string& objPath, 4186adcd6dSAndrew Geissler const std::string& service) 4286adcd6dSAndrew Geissler { 4386adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; 4486adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 4586adcd6dSAndrew Geissler [](const boost::system::error_code error_code) { 4686adcd6dSAndrew Geissler if (error_code) 4786adcd6dSAndrew Geissler { 4886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 4986adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); 5086adcd6dSAndrew Geissler } 5186adcd6dSAndrew Geissler }, 5286adcd6dSAndrew Geissler service, objPath, "org.freedesktop.DBus.Properties", "Set", 5386adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation", "RequestedActivation", 5486adcd6dSAndrew Geissler std::variant<std::string>( 5586adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation.RequestedActivations." 5686adcd6dSAndrew Geissler "Active")); 5786adcd6dSAndrew Geissler } 580554c984SAndrew Geissler 590554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 600554c984SAndrew Geissler // then no asyncResp updates will occur 6186adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 62fe306728SJames Feist sdbusplus::message::message& m, 63fe306728SJames Feist const crow::Request& req) 6486adcd6dSAndrew Geissler { 6586adcd6dSAndrew Geissler std::vector<std::pair< 6686adcd6dSAndrew Geissler std::string, 6786adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6886adcd6dSAndrew Geissler interfacesProperties; 6986adcd6dSAndrew Geissler 7086adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 7186adcd6dSAndrew Geissler 7286adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 7386adcd6dSAndrew Geissler 7486adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7586adcd6dSAndrew Geissler for (auto& interface : interfacesProperties) 7686adcd6dSAndrew Geissler { 7786adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7886adcd6dSAndrew Geissler 7986adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 8086adcd6dSAndrew Geissler { 8186adcd6dSAndrew Geissler // Found our interface, disable callbacks 8286adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 8386adcd6dSAndrew Geissler 8486adcd6dSAndrew Geissler // Retrieve service and activate 8586adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 86fe306728SJames Feist [objPath, asyncResp, 87fe306728SJames Feist req](const boost::system::error_code error_code, 8886adcd6dSAndrew Geissler const std::vector<std::pair< 8986adcd6dSAndrew Geissler std::string, std::vector<std::string>>>& objInfo) { 9086adcd6dSAndrew Geissler if (error_code) 9186adcd6dSAndrew Geissler { 9286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 9386adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 9486adcd6dSAndrew Geissler << error_code.message(); 950554c984SAndrew Geissler if (asyncResp) 960554c984SAndrew Geissler { 9786adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 980554c984SAndrew Geissler } 9986adcd6dSAndrew Geissler cleanUp(); 10086adcd6dSAndrew Geissler return; 10186adcd6dSAndrew Geissler } 10286adcd6dSAndrew Geissler // Ensure we only got one service back 10386adcd6dSAndrew Geissler if (objInfo.size() != 1) 10486adcd6dSAndrew Geissler { 10586adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 10686adcd6dSAndrew Geissler << objInfo.size(); 1070554c984SAndrew Geissler if (asyncResp) 1080554c984SAndrew Geissler { 10986adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 1100554c984SAndrew Geissler } 11186adcd6dSAndrew Geissler cleanUp(); 11286adcd6dSAndrew Geissler return; 11386adcd6dSAndrew Geissler } 11486adcd6dSAndrew Geissler // cancel timer only when 11586adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 11686adcd6dSAndrew Geissler // is added 11786adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 11886adcd6dSAndrew Geissler 11986adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 1200554c984SAndrew Geissler if (asyncResp) 1210554c984SAndrew Geissler { 12232898ceaSJames Feist std::shared_ptr<task::TaskData> task = 12332898ceaSJames Feist task::TaskData::createTask( 12432898ceaSJames Feist [](boost::system::error_code ec, 12532898ceaSJames Feist sdbusplus::message::message& msg, 126*1214b7e7SGunnar Mills const std::shared_ptr<task::TaskData>& 127*1214b7e7SGunnar Mills taskData) { 12832898ceaSJames Feist if (ec) 12932898ceaSJames Feist { 13032898ceaSJames Feist return task::completed; 13132898ceaSJames Feist } 13232898ceaSJames Feist 13332898ceaSJames Feist std::string iface; 13432898ceaSJames Feist boost::container::flat_map< 135fd9ab9e1SJames Feist std::string, 136fd9ab9e1SJames Feist std::variant<std::string, uint8_t>> 13732898ceaSJames Feist values; 138fd9ab9e1SJames Feist 139fd9ab9e1SJames Feist std::string index = 140fd9ab9e1SJames Feist std::to_string(taskData->index); 14132898ceaSJames Feist msg.read(iface, values); 142fd9ab9e1SJames Feist 143fd9ab9e1SJames Feist if (iface == "xyz.openbmc_project.Software." 144fd9ab9e1SJames Feist "Activation") 145fd9ab9e1SJames Feist { 14632898ceaSJames Feist auto findActivation = 14732898ceaSJames Feist values.find("Activation"); 14832898ceaSJames Feist if (findActivation == values.end()) 14932898ceaSJames Feist { 15032898ceaSJames Feist return !task::completed; 15132898ceaSJames Feist } 15232898ceaSJames Feist std::string* state = 15332898ceaSJames Feist std::get_if<std::string>( 15432898ceaSJames Feist &(findActivation->second)); 15532898ceaSJames Feist 15632898ceaSJames Feist if (state == nullptr) 15732898ceaSJames Feist { 15832898ceaSJames Feist taskData->messages.emplace_back( 15932898ceaSJames Feist messages::internalError()); 16032898ceaSJames Feist return task::completed; 16132898ceaSJames Feist } 16232898ceaSJames Feist 163fd9ab9e1SJames Feist if (boost::ends_with(*state, 164fd9ab9e1SJames Feist "Invalid") || 16532898ceaSJames Feist boost::ends_with(*state, "Failed")) 16632898ceaSJames Feist { 16732898ceaSJames Feist taskData->state = "Exception"; 16832898ceaSJames Feist taskData->status = "Warning"; 16932898ceaSJames Feist taskData->messages.emplace_back( 170e5d5006bSJames Feist messages::taskAborted(index)); 17132898ceaSJames Feist return task::completed; 17232898ceaSJames Feist } 17332898ceaSJames Feist 17432898ceaSJames Feist if (boost::ends_with(*state, "Staged")) 17532898ceaSJames Feist { 176fd9ab9e1SJames Feist taskData->state = "Stopping"; 177fd9ab9e1SJames Feist taskData->messages.emplace_back( 178fd9ab9e1SJames Feist messages::taskPaused(index)); 179fd9ab9e1SJames Feist 180fd9ab9e1SJames Feist // its staged, set a long timer to 181fd9ab9e1SJames Feist // allow them time to complete the 182fd9ab9e1SJames Feist // update (probably cycle the 183fd9ab9e1SJames Feist // system) if this expires then 184fd9ab9e1SJames Feist // task will be cancelled 185fd9ab9e1SJames Feist taskData->extendTimer( 186fd9ab9e1SJames Feist std::chrono::hours(5)); 18732898ceaSJames Feist return !task::completed; 18832898ceaSJames Feist } 18932898ceaSJames Feist 19032898ceaSJames Feist if (boost::ends_with(*state, "Active")) 19132898ceaSJames Feist { 19232898ceaSJames Feist taskData->messages.emplace_back( 193fd9ab9e1SJames Feist messages::taskCompletedOK( 194fd9ab9e1SJames Feist index)); 19532898ceaSJames Feist taskData->state = "Completed"; 19632898ceaSJames Feist return task::completed; 19732898ceaSJames Feist } 198fd9ab9e1SJames Feist } 199fd9ab9e1SJames Feist else if (iface == 200fd9ab9e1SJames Feist "xyz.openbmc_project.Software." 201fd9ab9e1SJames Feist "ActivationProgress") 202fd9ab9e1SJames Feist { 203fd9ab9e1SJames Feist auto findProgress = 204fd9ab9e1SJames Feist values.find("Progress"); 205fd9ab9e1SJames Feist if (findProgress == values.end()) 206fd9ab9e1SJames Feist { 207fd9ab9e1SJames Feist return !task::completed; 208fd9ab9e1SJames Feist } 209fd9ab9e1SJames Feist uint8_t* progress = 210fd9ab9e1SJames Feist std::get_if<uint8_t>( 211fd9ab9e1SJames Feist &(findProgress->second)); 212fd9ab9e1SJames Feist 213fd9ab9e1SJames Feist if (progress == nullptr) 214fd9ab9e1SJames Feist { 215fd9ab9e1SJames Feist taskData->messages.emplace_back( 216fd9ab9e1SJames Feist messages::internalError()); 217fd9ab9e1SJames Feist return task::completed; 218fd9ab9e1SJames Feist } 219fd9ab9e1SJames Feist taskData->messages.emplace_back( 220fd9ab9e1SJames Feist messages::taskProgressChanged( 221fd9ab9e1SJames Feist index, static_cast<size_t>( 222fd9ab9e1SJames Feist *progress))); 223fd9ab9e1SJames Feist 224fd9ab9e1SJames Feist // if we're getting status updates it's 225fd9ab9e1SJames Feist // still alive, update timer 226fd9ab9e1SJames Feist taskData->extendTimer( 227fd9ab9e1SJames Feist std::chrono::minutes(5)); 228fd9ab9e1SJames Feist } 22932898ceaSJames Feist 23032898ceaSJames Feist // as firmware update often results in a 23132898ceaSJames Feist // reboot, the task may never "complete" 23232898ceaSJames Feist // unless it is an error 23332898ceaSJames Feist 23432898ceaSJames Feist return !task::completed; 23532898ceaSJames Feist }, 23632898ceaSJames Feist "type='signal',interface='org.freedesktop.DBus." 23732898ceaSJames Feist "Properties'," 238fd9ab9e1SJames Feist "member='PropertiesChanged',path='" + 23932898ceaSJames Feist objPath.str + "'"); 24032898ceaSJames Feist task->startTimer(std::chrono::minutes(5)); 24132898ceaSJames Feist task->populateResp(asyncResp->res); 242fe306728SJames Feist task->payload.emplace(req); 2430554c984SAndrew Geissler } 24486adcd6dSAndrew Geissler fwUpdateInProgress = false; 24586adcd6dSAndrew Geissler }, 24686adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 24786adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 24886adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 24986adcd6dSAndrew Geissler std::array<const char*, 1>{ 25086adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 25186adcd6dSAndrew Geissler } 25286adcd6dSAndrew Geissler } 25386adcd6dSAndrew Geissler } 25486adcd6dSAndrew Geissler 2550554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 2560554c984SAndrew Geissler // then no asyncResp updates will occur 25786adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 2580554c984SAndrew Geissler const crow::Request& req, 2590554c984SAndrew Geissler int timeoutTimeSeconds = 5) 26086adcd6dSAndrew Geissler { 26186adcd6dSAndrew Geissler // Only allow one FW update at a time 26286adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 26386adcd6dSAndrew Geissler { 2640554c984SAndrew Geissler if (asyncResp) 2650554c984SAndrew Geissler { 26686adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 2670554c984SAndrew Geissler } 26886adcd6dSAndrew Geissler return; 26986adcd6dSAndrew Geissler } 27086adcd6dSAndrew Geissler 2710554c984SAndrew Geissler fwAvailableTimer = 272271584abSEd Tanous std::make_unique<boost::asio::steady_timer>(*req.ioService); 27386adcd6dSAndrew Geissler 274271584abSEd Tanous fwAvailableTimer->expires_after(std::chrono::seconds(timeoutTimeSeconds)); 27586adcd6dSAndrew Geissler 27686adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 27786adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code& ec) { 27886adcd6dSAndrew Geissler cleanUp(); 27986adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 28086adcd6dSAndrew Geissler { 28186adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 28286adcd6dSAndrew Geissler return; 28386adcd6dSAndrew Geissler } 28486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 28586adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 28686adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 28786adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 28886adcd6dSAndrew Geissler if (ec) 28986adcd6dSAndrew Geissler { 29086adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 29186adcd6dSAndrew Geissler return; 29286adcd6dSAndrew Geissler } 2930554c984SAndrew Geissler if (asyncResp) 2940554c984SAndrew Geissler { 29586adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 2960554c984SAndrew Geissler } 29786adcd6dSAndrew Geissler }); 29886adcd6dSAndrew Geissler 299fe306728SJames Feist auto callback = [asyncResp, req](sdbusplus::message::message& m) { 30086adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 301fe306728SJames Feist softwareInterfaceAdded(asyncResp, m, req); 30286adcd6dSAndrew Geissler }; 30386adcd6dSAndrew Geissler 30486adcd6dSAndrew Geissler fwUpdateInProgress = true; 30586adcd6dSAndrew Geissler 30686adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 30786adcd6dSAndrew Geissler *crow::connections::systemBus, 30886adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 30986adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 31086adcd6dSAndrew Geissler callback); 31186adcd6dSAndrew Geissler } 312729dae72SJennifer Lee 3130554c984SAndrew Geissler /** 3140554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 3150554c984SAndrew Geissler * SimpleUpdate action. 3160554c984SAndrew Geissler */ 3170554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 3180554c984SAndrew Geissler { 3190554c984SAndrew Geissler public: 3200554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp& app) : 3210554c984SAndrew Geissler Node(app, 3220554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 3230554c984SAndrew Geissler { 3240554c984SAndrew Geissler entityPrivileges = { 3250554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 3260554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 3270554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 3280554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 3290554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 3300554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 3310554c984SAndrew Geissler } 3320554c984SAndrew Geissler 3330554c984SAndrew Geissler private: 3340554c984SAndrew Geissler void doPost(crow::Response& res, const crow::Request& req, 3350554c984SAndrew Geissler const std::vector<std::string>& params) override 3360554c984SAndrew Geissler { 3370554c984SAndrew Geissler std::optional<std::string> transferProtocol; 3380554c984SAndrew Geissler std::string imageURI; 3390554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 3400554c984SAndrew Geissler 3410554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 3420554c984SAndrew Geissler 3430554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 3440554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 3450554c984SAndrew Geissler // within it. 3460554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 3470554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 3480554c984SAndrew Geissler 3490554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 3500554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 3510554c984SAndrew Geissler { 3520554c984SAndrew Geissler BMCWEB_LOG_DEBUG 3530554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 3540554c984SAndrew Geissler return; 3550554c984SAndrew Geissler } 3560554c984SAndrew Geissler if (!transferProtocol) 3570554c984SAndrew Geissler { 3580554c984SAndrew Geissler // Must be option 2 3590554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 3600554c984SAndrew Geissler size_t separator = imageURI.find(":"); 3610554c984SAndrew Geissler if ((separator == std::string::npos) || 3620554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3630554c984SAndrew Geissler { 3640554c984SAndrew Geissler messages::actionParameterValueTypeError( 3650554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 3660554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3670554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 3680554c984SAndrew Geissler << imageURI; 3690554c984SAndrew Geissler return; 3700554c984SAndrew Geissler } 3710554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 3720554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 3730554c984SAndrew Geissler boost::to_upper(*transferProtocol); 3740554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 3750554c984SAndrew Geissler << *transferProtocol; 3760554c984SAndrew Geissler 3770554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 3780554c984SAndrew Geissler // below 3790554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 3800554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 3810554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 3820554c984SAndrew Geissler } 3830554c984SAndrew Geissler 3840554c984SAndrew Geissler // OpenBMC currently only supports TFTP 3850554c984SAndrew Geissler if (*transferProtocol != "TFTP") 3860554c984SAndrew Geissler { 3870554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 3880554c984SAndrew Geissler "TransferProtocol", 3890554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 3900554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 3910554c984SAndrew Geissler << *transferProtocol; 3920554c984SAndrew Geissler return; 3930554c984SAndrew Geissler } 3940554c984SAndrew Geissler 3950554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 3960554c984SAndrew Geissler size_t separator = imageURI.find("/"); 3970554c984SAndrew Geissler if ((separator == std::string::npos) || 3980554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 3990554c984SAndrew Geissler { 4000554c984SAndrew Geissler messages::actionParameterValueTypeError( 4010554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 4020554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 4030554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 4040554c984SAndrew Geissler return; 4050554c984SAndrew Geissler } 4060554c984SAndrew Geissler 4070554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 4080554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 4090554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 4100554c984SAndrew Geissler 4110554c984SAndrew Geissler // Setup callback for when new software detected 4120554c984SAndrew Geissler // Give TFTP 2 minutes to complete 4130554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 4140554c984SAndrew Geissler 4150554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 4160554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 4170554c984SAndrew Geissler // has been started. The callback above will ensure the activate 4180554c984SAndrew Geissler // is started once the download has completed 4190554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 4200554c984SAndrew Geissler 4210554c984SAndrew Geissler // Call TFTP service 4220554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 4230554c984SAndrew Geissler [](const boost::system::error_code ec) { 4240554c984SAndrew Geissler if (ec) 4250554c984SAndrew Geissler { 4260554c984SAndrew Geissler // messages::internalError(asyncResp->res); 4270554c984SAndrew Geissler cleanUp(); 4280554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 4290554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 4300554c984SAndrew Geissler } 4310554c984SAndrew Geissler else 4320554c984SAndrew Geissler { 4330554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 4340554c984SAndrew Geissler } 4350554c984SAndrew Geissler }, 4360554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 4370554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 4380554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 4390554c984SAndrew Geissler 4400554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 4410554c984SAndrew Geissler } 4420554c984SAndrew Geissler }; 4430554c984SAndrew Geissler 4441abe55efSEd Tanous class UpdateService : public Node 4451abe55efSEd Tanous { 446729dae72SJennifer Lee public: 4471abe55efSEd Tanous UpdateService(CrowApp& app) : Node(app, "/redfish/v1/UpdateService/") 4481abe55efSEd Tanous { 449729dae72SJennifer Lee entityPrivileges = { 450729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 451729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 452729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 453729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 454729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 455729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 456729dae72SJennifer Lee } 457729dae72SJennifer Lee 458729dae72SJennifer Lee private: 45955c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 4601abe55efSEd Tanous const std::vector<std::string>& params) override 4611abe55efSEd Tanous { 462274dfe62SJayashankar Padath std::shared_ptr<AsyncResp> aResp = std::make_shared<AsyncResp>(res); 463274dfe62SJayashankar Padath res.jsonValue["@odata.type"] = "#UpdateService.v1_4_0.UpdateService"; 4640f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 4650f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 4660f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 4670f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 4680f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 4690f74e643SEd Tanous // UpdateService cannot be disabled 4700f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 4710f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 4720f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 4730554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 4740554c984SAndrew Geissler // Update Actions object. 4750554c984SAndrew Geissler nlohmann::json& updateSvcSimpleUpdate = 4760554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 4770554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 4780554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 4790554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 4800554c984SAndrew Geissler "TFTP"}; 4810554c984SAndrew Geissler #endif 482274dfe62SJayashankar Padath // Get the current ApplyTime value 483274dfe62SJayashankar Padath crow::connections::systemBus->async_method_call( 484274dfe62SJayashankar Padath [aResp](const boost::system::error_code ec, 485274dfe62SJayashankar Padath const std::variant<std::string>& applyTime) { 486274dfe62SJayashankar Padath if (ec) 487274dfe62SJayashankar Padath { 488274dfe62SJayashankar Padath BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 489274dfe62SJayashankar Padath messages::internalError(aResp->res); 490274dfe62SJayashankar Padath return; 491274dfe62SJayashankar Padath } 492274dfe62SJayashankar Padath 493274dfe62SJayashankar Padath const std::string* s = std::get_if<std::string>(&applyTime); 494274dfe62SJayashankar Padath if (s == nullptr) 495274dfe62SJayashankar Padath { 496274dfe62SJayashankar Padath return; 497274dfe62SJayashankar Padath } 498274dfe62SJayashankar Padath // Store the ApplyTime Value 499274dfe62SJayashankar Padath if (*s == "xyz.openbmc_project.Software.ApplyTime." 500274dfe62SJayashankar Padath "RequestedApplyTimes.Immediate") 501274dfe62SJayashankar Padath { 502274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 503274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 504274dfe62SJayashankar Padath "Immediate"; 505274dfe62SJayashankar Padath } 506274dfe62SJayashankar Padath else if (*s == "xyz.openbmc_project.Software.ApplyTime." 507274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset") 508274dfe62SJayashankar Padath { 509274dfe62SJayashankar Padath aResp->res.jsonValue["HttpPushUriOptions"] 510274dfe62SJayashankar Padath ["HttpPushUriApplyTime"]["ApplyTime"] = 511274dfe62SJayashankar Padath "OnReset"; 512274dfe62SJayashankar Padath } 513274dfe62SJayashankar Padath }, 514274dfe62SJayashankar Padath "xyz.openbmc_project.Settings", 515274dfe62SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 516274dfe62SJayashankar Padath "org.freedesktop.DBus.Properties", "Get", 517274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime"); 518729dae72SJennifer Lee } 5190e7de46fSAndrew Geissler 520fa1a5a38SJayashankar Padath void doPatch(crow::Response& res, const crow::Request& req, 521fa1a5a38SJayashankar Padath const std::vector<std::string>& params) override 522fa1a5a38SJayashankar Padath { 523fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 524fa1a5a38SJayashankar Padath 525fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 526fa1a5a38SJayashankar Padath 527274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriOptions; 528274dfe62SJayashankar Padath if (!json_util::readJson(req, res, "HttpPushUriOptions", 529274dfe62SJayashankar Padath pushUriOptions)) 530fa1a5a38SJayashankar Padath { 531fa1a5a38SJayashankar Padath return; 532fa1a5a38SJayashankar Padath } 533fa1a5a38SJayashankar Padath 534274dfe62SJayashankar Padath if (pushUriOptions) 535274dfe62SJayashankar Padath { 536274dfe62SJayashankar Padath std::optional<nlohmann::json> pushUriApplyTime; 537274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriOptions, res, 538274dfe62SJayashankar Padath "HttpPushUriApplyTime", pushUriApplyTime)) 539274dfe62SJayashankar Padath { 540274dfe62SJayashankar Padath return; 541274dfe62SJayashankar Padath } 542274dfe62SJayashankar Padath 543274dfe62SJayashankar Padath if (pushUriApplyTime) 544274dfe62SJayashankar Padath { 545274dfe62SJayashankar Padath std::optional<std::string> applyTime; 546274dfe62SJayashankar Padath if (!json_util::readJson(*pushUriApplyTime, res, "ApplyTime", 547274dfe62SJayashankar Padath applyTime)) 548274dfe62SJayashankar Padath { 549274dfe62SJayashankar Padath return; 550274dfe62SJayashankar Padath } 551274dfe62SJayashankar Padath 552274dfe62SJayashankar Padath if (applyTime) 553fa1a5a38SJayashankar Padath { 554fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 555fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 556fa1a5a38SJayashankar Padath { 557274dfe62SJayashankar Padath applyTimeNewVal = 558274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 559fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 560fa1a5a38SJayashankar Padath } 561274dfe62SJayashankar Padath else if (applyTime == "OnReset") 562274dfe62SJayashankar Padath { 563274dfe62SJayashankar Padath applyTimeNewVal = 564274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime." 565274dfe62SJayashankar Padath "RequestedApplyTimes.OnReset"; 566274dfe62SJayashankar Padath } 567fa1a5a38SJayashankar Padath else 568fa1a5a38SJayashankar Padath { 569274dfe62SJayashankar Padath BMCWEB_LOG_INFO 570274dfe62SJayashankar Padath << "ApplyTime value is not in the list of " 571274dfe62SJayashankar Padath "acceptable values"; 572274dfe62SJayashankar Padath messages::propertyValueNotInList( 573274dfe62SJayashankar Padath asyncResp->res, *applyTime, "ApplyTime"); 574274dfe62SJayashankar Padath return; 575fa1a5a38SJayashankar Padath } 576fa1a5a38SJayashankar Padath 577fa1a5a38SJayashankar Padath // Set the requested image apply time value 578fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 579fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 580fa1a5a38SJayashankar Padath if (ec) 581fa1a5a38SJayashankar Padath { 582274dfe62SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " 583274dfe62SJayashankar Padath << ec; 584fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 585fa1a5a38SJayashankar Padath return; 586fa1a5a38SJayashankar Padath } 587fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 588fa1a5a38SJayashankar Padath }, 589fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 590fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 591fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 592274dfe62SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", 593274dfe62SJayashankar Padath "RequestedApplyTime", 594fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 595fa1a5a38SJayashankar Padath } 596274dfe62SJayashankar Padath } 597fa1a5a38SJayashankar Padath } 598fa1a5a38SJayashankar Padath } 599fa1a5a38SJayashankar Padath 600acb7cfb4SJennifer Lee void doPost(crow::Response& res, const crow::Request& req, 6011abe55efSEd Tanous const std::vector<std::string>& params) override 6021abe55efSEd Tanous { 603acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 604acb7cfb4SJennifer Lee 6050e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 606acb7cfb4SJennifer Lee 60786adcd6dSAndrew Geissler // Setup callback for when new software detected 60886adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 609acb7cfb4SJennifer Lee 610acb7cfb4SJennifer Lee std::string filepath( 611acb7cfb4SJennifer Lee "/tmp/images/" + 612acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 613acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 614acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 615acb7cfb4SJennifer Lee std::ofstream::trunc); 616acb7cfb4SJennifer Lee out << req.body; 617acb7cfb4SJennifer Lee out.close(); 618acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 619acb7cfb4SJennifer Lee } 620729dae72SJennifer Lee }; 621729dae72SJennifer Lee 6221abe55efSEd Tanous class SoftwareInventoryCollection : public Node 6231abe55efSEd Tanous { 624729dae72SJennifer Lee public: 625729dae72SJennifer Lee template <typename CrowApp> 6261abe55efSEd Tanous SoftwareInventoryCollection(CrowApp& app) : 6271abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 6281abe55efSEd Tanous { 629729dae72SJennifer Lee entityPrivileges = { 630729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 631729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 632729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 633729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 634729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 635729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 636729dae72SJennifer Lee } 637729dae72SJennifer Lee 638729dae72SJennifer Lee private: 63955c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 6401abe55efSEd Tanous const std::vector<std::string>& params) override 6411abe55efSEd Tanous { 642c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6430f74e643SEd Tanous res.jsonValue["@odata.type"] = 6440f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 6450f74e643SEd Tanous res.jsonValue["@odata.id"] = 6460f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 6470f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 648c711bf86SEd Tanous 649c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 650c711bf86SEd Tanous [asyncResp]( 651c711bf86SEd Tanous const boost::system::error_code ec, 6526c4eb9deSJennifer Lee const std::vector<std::pair< 6531abe55efSEd Tanous std::string, std::vector<std::pair< 654*1214b7e7SGunnar Mills std::string, std::vector<std::string>>>>>& 655*1214b7e7SGunnar Mills subtree) { 6561abe55efSEd Tanous if (ec) 6571abe55efSEd Tanous { 658f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6596c4eb9deSJennifer Lee return; 660729dae72SJennifer Lee } 661c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 662c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 6636c4eb9deSJennifer Lee 6641abe55efSEd Tanous for (auto& obj : subtree) 6651abe55efSEd Tanous { 666f4b65ab1SJennifer Lee // if can't parse fw id then return 66727826b5fSEd Tanous std::size_t idPos; 66827826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 669f4b65ab1SJennifer Lee { 670f12894f8SJason M. Bills messages::internalError(asyncResp->res); 671f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 672f4b65ab1SJennifer Lee return; 673f4b65ab1SJennifer Lee } 674f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 675f4b65ab1SJennifer Lee 676c711bf86SEd Tanous nlohmann::json& members = 677c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 678c711bf86SEd Tanous members.push_back( 679f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 6801abe55efSEd Tanous "FirmwareInventory/" + 681f4b65ab1SJennifer Lee swId}}); 682e0dd8057SAndrew Geissler asyncResp->res.jsonValue["Members@odata.count"] = 683c711bf86SEd Tanous members.size(); 6846c4eb9deSJennifer Lee } 685c711bf86SEd Tanous }, 6862830a9cfSAndrew Geissler // Note that only firmware levels associated with a device are 6872830a9cfSAndrew Geissler // stored under /xyz/openbmc_project/software therefore to ensure 6882830a9cfSAndrew Geissler // only real FirmwareInventory items are returned, this full object 6892830a9cfSAndrew Geissler // path must be used here as input to mapper 690c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 691c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 6922830a9cfSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetSubTree", 6932830a9cfSAndrew Geissler "/xyz/openbmc_project/software", static_cast<int32_t>(0), 694*1214b7e7SGunnar Mills std::array<const char*, 1>{"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>& params) 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< 762*1214b7e7SGunnar Mills std::string, std::vector<std::string>>>>>& 763*1214b7e7SGunnar Mills 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< 776*1214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 777*1214b7e7SGunnar Mills 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), 899*1214b7e7SGunnar Mills std::array<const char*, 1>{"xyz.openbmc_project.Software.Version"}); 9006c4eb9deSJennifer Lee } 901729dae72SJennifer Lee }; 902729dae72SJennifer Lee 903729dae72SJennifer Lee } // namespace redfish 904