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 3286adcd6dSAndrew Geissler static std::unique_ptr<boost::asio::deadline_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 } 57*0554c984SAndrew Geissler 58*0554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 59*0554c984SAndrew Geissler // then no asyncResp updates will occur 6086adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 6186adcd6dSAndrew Geissler sdbusplus::message::message &m) 6286adcd6dSAndrew Geissler { 6386adcd6dSAndrew Geissler std::vector<std::pair< 6486adcd6dSAndrew Geissler std::string, 6586adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6686adcd6dSAndrew Geissler interfacesProperties; 6786adcd6dSAndrew Geissler 6886adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 6986adcd6dSAndrew Geissler 7086adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 7186adcd6dSAndrew Geissler 7286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7386adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 7486adcd6dSAndrew Geissler { 7586adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7686adcd6dSAndrew Geissler 7786adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 7886adcd6dSAndrew Geissler { 7986adcd6dSAndrew Geissler // Found our interface, disable callbacks 8086adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 8186adcd6dSAndrew Geissler 8286adcd6dSAndrew Geissler // Retrieve service and activate 8386adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 8486adcd6dSAndrew Geissler [objPath, asyncResp]( 8586adcd6dSAndrew Geissler const boost::system::error_code error_code, 8686adcd6dSAndrew Geissler const std::vector<std::pair< 8786adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 8886adcd6dSAndrew Geissler if (error_code) 8986adcd6dSAndrew Geissler { 9086adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 9186adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 9286adcd6dSAndrew Geissler << error_code.message(); 93*0554c984SAndrew Geissler if (asyncResp) 94*0554c984SAndrew Geissler { 9586adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 96*0554c984SAndrew Geissler } 9786adcd6dSAndrew Geissler cleanUp(); 9886adcd6dSAndrew Geissler return; 9986adcd6dSAndrew Geissler } 10086adcd6dSAndrew Geissler // Ensure we only got one service back 10186adcd6dSAndrew Geissler if (objInfo.size() != 1) 10286adcd6dSAndrew Geissler { 10386adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 10486adcd6dSAndrew Geissler << objInfo.size(); 105*0554c984SAndrew Geissler if (asyncResp) 106*0554c984SAndrew Geissler { 10786adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 108*0554c984SAndrew Geissler } 10986adcd6dSAndrew Geissler cleanUp(); 11086adcd6dSAndrew Geissler return; 11186adcd6dSAndrew Geissler } 11286adcd6dSAndrew Geissler // cancel timer only when 11386adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 11486adcd6dSAndrew Geissler // is added 11586adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 11686adcd6dSAndrew Geissler 11786adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 118*0554c984SAndrew Geissler if (asyncResp) 119*0554c984SAndrew Geissler { 12086adcd6dSAndrew Geissler redfish::messages::success(asyncResp->res); 121*0554c984SAndrew Geissler } 12286adcd6dSAndrew Geissler fwUpdateInProgress = false; 12386adcd6dSAndrew Geissler }, 12486adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 12586adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 12686adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 12786adcd6dSAndrew Geissler std::array<const char *, 1>{ 12886adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 12986adcd6dSAndrew Geissler } 13086adcd6dSAndrew Geissler } 13186adcd6dSAndrew Geissler } 13286adcd6dSAndrew Geissler 133*0554c984SAndrew Geissler // Note that asyncResp can be either a valid pointer or nullptr. If nullptr 134*0554c984SAndrew Geissler // then no asyncResp updates will occur 13586adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 136*0554c984SAndrew Geissler const crow::Request &req, 137*0554c984SAndrew Geissler int timeoutTimeSeconds = 5) 13886adcd6dSAndrew Geissler { 13986adcd6dSAndrew Geissler // Only allow one FW update at a time 14086adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 14186adcd6dSAndrew Geissler { 142*0554c984SAndrew Geissler if (asyncResp) 143*0554c984SAndrew Geissler { 14486adcd6dSAndrew Geissler asyncResp->res.addHeader("Retry-After", "30"); 14586adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 146*0554c984SAndrew Geissler } 14786adcd6dSAndrew Geissler return; 14886adcd6dSAndrew Geissler } 14986adcd6dSAndrew Geissler 150*0554c984SAndrew Geissler fwAvailableTimer = 151*0554c984SAndrew Geissler std::make_unique<boost::asio::deadline_timer>(*req.ioService); 15286adcd6dSAndrew Geissler 153*0554c984SAndrew Geissler fwAvailableTimer->expires_from_now( 154*0554c984SAndrew Geissler boost::posix_time::seconds(timeoutTimeSeconds)); 15586adcd6dSAndrew Geissler 15686adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 15786adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 15886adcd6dSAndrew Geissler cleanUp(); 15986adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 16086adcd6dSAndrew Geissler { 16186adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 16286adcd6dSAndrew Geissler return; 16386adcd6dSAndrew Geissler } 16486adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 16586adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 16686adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 16786adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 16886adcd6dSAndrew Geissler if (ec) 16986adcd6dSAndrew Geissler { 17086adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 17186adcd6dSAndrew Geissler return; 17286adcd6dSAndrew Geissler } 173*0554c984SAndrew Geissler if (asyncResp) 174*0554c984SAndrew Geissler { 17586adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 176*0554c984SAndrew Geissler } 17786adcd6dSAndrew Geissler }); 17886adcd6dSAndrew Geissler 17986adcd6dSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 18086adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 18186adcd6dSAndrew Geissler softwareInterfaceAdded(asyncResp, m); 18286adcd6dSAndrew Geissler }; 18386adcd6dSAndrew Geissler 18486adcd6dSAndrew Geissler fwUpdateInProgress = true; 18586adcd6dSAndrew Geissler 18686adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 18786adcd6dSAndrew Geissler *crow::connections::systemBus, 18886adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 18986adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 19086adcd6dSAndrew Geissler callback); 19186adcd6dSAndrew Geissler } 192729dae72SJennifer Lee 193*0554c984SAndrew Geissler /** 194*0554c984SAndrew Geissler * UpdateServiceActionsSimpleUpdate class supports handle POST method for 195*0554c984SAndrew Geissler * SimpleUpdate action. 196*0554c984SAndrew Geissler */ 197*0554c984SAndrew Geissler class UpdateServiceActionsSimpleUpdate : public Node 198*0554c984SAndrew Geissler { 199*0554c984SAndrew Geissler public: 200*0554c984SAndrew Geissler UpdateServiceActionsSimpleUpdate(CrowApp &app) : 201*0554c984SAndrew Geissler Node(app, 202*0554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate/") 203*0554c984SAndrew Geissler { 204*0554c984SAndrew Geissler entityPrivileges = { 205*0554c984SAndrew Geissler {boost::beast::http::verb::get, {{"Login"}}}, 206*0554c984SAndrew Geissler {boost::beast::http::verb::head, {{"Login"}}}, 207*0554c984SAndrew Geissler {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 208*0554c984SAndrew Geissler {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 209*0554c984SAndrew Geissler {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 210*0554c984SAndrew Geissler {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 211*0554c984SAndrew Geissler } 212*0554c984SAndrew Geissler 213*0554c984SAndrew Geissler private: 214*0554c984SAndrew Geissler void doPost(crow::Response &res, const crow::Request &req, 215*0554c984SAndrew Geissler const std::vector<std::string> ¶ms) override 216*0554c984SAndrew Geissler { 217*0554c984SAndrew Geissler std::optional<std::string> transferProtocol; 218*0554c984SAndrew Geissler std::string imageURI; 219*0554c984SAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 220*0554c984SAndrew Geissler 221*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Enter UpdateService.SimpleUpdate doPost"; 222*0554c984SAndrew Geissler 223*0554c984SAndrew Geissler // User can pass in both TransferProtocol and ImageURI parameters or 224*0554c984SAndrew Geissler // they can pass in just the ImageURI with the transfer protocl embedded 225*0554c984SAndrew Geissler // within it. 226*0554c984SAndrew Geissler // 1) TransferProtocol:TFTP ImageURI:1.1.1.1/myfile.bin 227*0554c984SAndrew Geissler // 2) ImageURI:tftp://1.1.1.1/myfile.bin 228*0554c984SAndrew Geissler 229*0554c984SAndrew Geissler if (!json_util::readJson(req, asyncResp->res, "TransferProtocol", 230*0554c984SAndrew Geissler transferProtocol, "ImageURI", imageURI)) 231*0554c984SAndrew Geissler { 232*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG 233*0554c984SAndrew Geissler << "Missing TransferProtocol or ImageURI parameter"; 234*0554c984SAndrew Geissler return; 235*0554c984SAndrew Geissler } 236*0554c984SAndrew Geissler if (!transferProtocol) 237*0554c984SAndrew Geissler { 238*0554c984SAndrew Geissler // Must be option 2 239*0554c984SAndrew Geissler // Verify ImageURI has transfer protocol in it 240*0554c984SAndrew Geissler size_t separator = imageURI.find(":"); 241*0554c984SAndrew Geissler if ((separator == std::string::npos) || 242*0554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 243*0554c984SAndrew Geissler { 244*0554c984SAndrew Geissler messages::actionParameterValueTypeError( 245*0554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 246*0554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 247*0554c984SAndrew Geissler BMCWEB_LOG_ERROR << "ImageURI missing transfer protocol: " 248*0554c984SAndrew Geissler << imageURI; 249*0554c984SAndrew Geissler return; 250*0554c984SAndrew Geissler } 251*0554c984SAndrew Geissler transferProtocol = imageURI.substr(0, separator); 252*0554c984SAndrew Geissler // Ensure protocol is upper case for a common comparison path below 253*0554c984SAndrew Geissler boost::to_upper(*transferProtocol); 254*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Encoded transfer protocol " 255*0554c984SAndrew Geissler << *transferProtocol; 256*0554c984SAndrew Geissler 257*0554c984SAndrew Geissler // Adjust imageURI to not have the protocol on it for parsing 258*0554c984SAndrew Geissler // below 259*0554c984SAndrew Geissler // ex. tftp://1.1.1.1/myfile.bin -> 1.1.1.1/myfile.bin 260*0554c984SAndrew Geissler imageURI = imageURI.substr(separator + 3); 261*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Adjusted imageUri " << imageURI; 262*0554c984SAndrew Geissler } 263*0554c984SAndrew Geissler 264*0554c984SAndrew Geissler // OpenBMC currently only supports TFTP 265*0554c984SAndrew Geissler if (*transferProtocol != "TFTP") 266*0554c984SAndrew Geissler { 267*0554c984SAndrew Geissler messages::actionParameterNotSupported(asyncResp->res, 268*0554c984SAndrew Geissler "TransferProtocol", 269*0554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 270*0554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Request incorrect protocol parameter: " 271*0554c984SAndrew Geissler << *transferProtocol; 272*0554c984SAndrew Geissler return; 273*0554c984SAndrew Geissler } 274*0554c984SAndrew Geissler 275*0554c984SAndrew Geissler // Format should be <IP or Hostname>/<file> for imageURI 276*0554c984SAndrew Geissler size_t separator = imageURI.find("/"); 277*0554c984SAndrew Geissler if ((separator == std::string::npos) || 278*0554c984SAndrew Geissler ((separator + 1) > imageURI.size())) 279*0554c984SAndrew Geissler { 280*0554c984SAndrew Geissler messages::actionParameterValueTypeError( 281*0554c984SAndrew Geissler asyncResp->res, imageURI, "ImageURI", 282*0554c984SAndrew Geissler "UpdateService.SimpleUpdate"); 283*0554c984SAndrew Geissler BMCWEB_LOG_ERROR << "Invalid ImageURI: " << imageURI; 284*0554c984SAndrew Geissler return; 285*0554c984SAndrew Geissler } 286*0554c984SAndrew Geissler 287*0554c984SAndrew Geissler std::string tftpServer = imageURI.substr(0, separator); 288*0554c984SAndrew Geissler std::string fwFile = imageURI.substr(separator + 1); 289*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Server: " << tftpServer + " File: " << fwFile; 290*0554c984SAndrew Geissler 291*0554c984SAndrew Geissler // Setup callback for when new software detected 292*0554c984SAndrew Geissler // Give TFTP 2 minutes to complete 293*0554c984SAndrew Geissler monitorForSoftwareAvailable(nullptr, req, 120); 294*0554c984SAndrew Geissler 295*0554c984SAndrew Geissler // TFTP can take up to 2 minutes depending on image size and 296*0554c984SAndrew Geissler // connection speed. Return to caller as soon as the TFTP operation 297*0554c984SAndrew Geissler // has been started. The callback above will ensure the activate 298*0554c984SAndrew Geissler // is started once the download has completed 299*0554c984SAndrew Geissler redfish::messages::success(asyncResp->res); 300*0554c984SAndrew Geissler 301*0554c984SAndrew Geissler // Call TFTP service 302*0554c984SAndrew Geissler crow::connections::systemBus->async_method_call( 303*0554c984SAndrew Geissler [](const boost::system::error_code ec) { 304*0554c984SAndrew Geissler if (ec) 305*0554c984SAndrew Geissler { 306*0554c984SAndrew Geissler // messages::internalError(asyncResp->res); 307*0554c984SAndrew Geissler cleanUp(); 308*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << ec; 309*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << ec.message(); 310*0554c984SAndrew Geissler } 311*0554c984SAndrew Geissler else 312*0554c984SAndrew Geissler { 313*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Call to DownloaViaTFTP Success"; 314*0554c984SAndrew Geissler } 315*0554c984SAndrew Geissler }, 316*0554c984SAndrew Geissler "xyz.openbmc_project.Software.Download", 317*0554c984SAndrew Geissler "/xyz/openbmc_project/software", "xyz.openbmc_project.Common.TFTP", 318*0554c984SAndrew Geissler "DownloadViaTFTP", fwFile, tftpServer); 319*0554c984SAndrew Geissler 320*0554c984SAndrew Geissler BMCWEB_LOG_DEBUG << "Exit UpdateService.SimpleUpdate doPost"; 321*0554c984SAndrew Geissler } 322*0554c984SAndrew Geissler }; 323*0554c984SAndrew Geissler 3241abe55efSEd Tanous class UpdateService : public Node 3251abe55efSEd Tanous { 326729dae72SJennifer Lee public: 3271abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 3281abe55efSEd Tanous { 329729dae72SJennifer Lee entityPrivileges = { 330729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 331729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 332729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 333729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 334729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 335729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 336729dae72SJennifer Lee } 337729dae72SJennifer Lee 338729dae72SJennifer Lee private: 33955c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 3401abe55efSEd Tanous const std::vector<std::string> ¶ms) override 3411abe55efSEd Tanous { 3420f74e643SEd Tanous res.jsonValue["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 3430f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 3440f74e643SEd Tanous res.jsonValue["@odata.context"] = 3450f74e643SEd Tanous "/redfish/v1/$metadata#UpdateService.UpdateService"; 3460f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 3470f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 3480f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 3490f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 3500f74e643SEd Tanous // UpdateService cannot be disabled 3510f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 3520f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 3530f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 354*0554c984SAndrew Geissler #ifdef BMCWEB_INSECURE_ENABLE_REDFISH_FW_TFTP_UPDATE 355*0554c984SAndrew Geissler // Update Actions object. 356*0554c984SAndrew Geissler nlohmann::json &updateSvcSimpleUpdate = 357*0554c984SAndrew Geissler res.jsonValue["Actions"]["#UpdateService.SimpleUpdate"]; 358*0554c984SAndrew Geissler updateSvcSimpleUpdate["target"] = 359*0554c984SAndrew Geissler "/redfish/v1/UpdateService/Actions/UpdateService.SimpleUpdate"; 360*0554c984SAndrew Geissler updateSvcSimpleUpdate["TransferProtocol@Redfish.AllowableValues"] = { 361*0554c984SAndrew Geissler "TFTP"}; 362*0554c984SAndrew Geissler #endif 363729dae72SJennifer Lee res.end(); 364729dae72SJennifer Lee } 3650e7de46fSAndrew Geissler 366fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 367fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 368fa1a5a38SJayashankar Padath { 369fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 370fa1a5a38SJayashankar Padath 371fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 372fa1a5a38SJayashankar Padath std::string applyTime; 373fa1a5a38SJayashankar Padath 374fa1a5a38SJayashankar Padath if (!json_util::readJson(req, res, "ApplyTime", applyTime)) 375fa1a5a38SJayashankar Padath { 376fa1a5a38SJayashankar Padath return; 377fa1a5a38SJayashankar Padath } 378fa1a5a38SJayashankar Padath 379fa1a5a38SJayashankar Padath if ((applyTime == "Immediate") || (applyTime == "OnReset")) 380fa1a5a38SJayashankar Padath { 381fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 382fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 383fa1a5a38SJayashankar Padath { 384fa1a5a38SJayashankar Padath applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime." 385fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 386fa1a5a38SJayashankar Padath } 387fa1a5a38SJayashankar Padath else 388fa1a5a38SJayashankar Padath { 389fa1a5a38SJayashankar Padath applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime." 390fa1a5a38SJayashankar Padath "RequestedApplyTimes.OnReset"; 391fa1a5a38SJayashankar Padath } 392fa1a5a38SJayashankar Padath 393fa1a5a38SJayashankar Padath // Set the requested image apply time value 394fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 395fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 396fa1a5a38SJayashankar Padath if (ec) 397fa1a5a38SJayashankar Padath { 398fa1a5a38SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 399fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 400fa1a5a38SJayashankar Padath return; 401fa1a5a38SJayashankar Padath } 402fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 403fa1a5a38SJayashankar Padath }, 404fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 405fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 406fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 407fa1a5a38SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime", 408fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 409fa1a5a38SJayashankar Padath } 410fa1a5a38SJayashankar Padath else 411fa1a5a38SJayashankar Padath { 412fa1a5a38SJayashankar Padath BMCWEB_LOG_INFO << "ApplyTime value is not in the list of " 413fa1a5a38SJayashankar Padath "acceptable values"; 414fa1a5a38SJayashankar Padath messages::propertyValueNotInList(asyncResp->res, applyTime, 415fa1a5a38SJayashankar Padath "ApplyTime"); 416fa1a5a38SJayashankar Padath } 417fa1a5a38SJayashankar Padath } 418fa1a5a38SJayashankar Padath 419acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 4201abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4211abe55efSEd Tanous { 422acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 423acb7cfb4SJennifer Lee 4240e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 425acb7cfb4SJennifer Lee 42686adcd6dSAndrew Geissler // Setup callback for when new software detected 42786adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 428acb7cfb4SJennifer Lee 429acb7cfb4SJennifer Lee std::string filepath( 430acb7cfb4SJennifer Lee "/tmp/images/" + 431acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 432acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 433acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 434acb7cfb4SJennifer Lee std::ofstream::trunc); 435acb7cfb4SJennifer Lee out << req.body; 436acb7cfb4SJennifer Lee out.close(); 437acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 438acb7cfb4SJennifer Lee } 439729dae72SJennifer Lee }; 440729dae72SJennifer Lee 4411abe55efSEd Tanous class SoftwareInventoryCollection : public Node 4421abe55efSEd Tanous { 443729dae72SJennifer Lee public: 444729dae72SJennifer Lee template <typename CrowApp> 4451abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 4461abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 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 { 461c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 4620f74e643SEd Tanous res.jsonValue["@odata.type"] = 4630f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 4640f74e643SEd Tanous res.jsonValue["@odata.id"] = 4650f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 4660f74e643SEd Tanous res.jsonValue["@odata.context"] = 4670f74e643SEd Tanous "/redfish/v1/" 4680f74e643SEd Tanous "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 4690f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 470c711bf86SEd Tanous 471c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 472c711bf86SEd Tanous [asyncResp]( 473c711bf86SEd Tanous const boost::system::error_code ec, 4746c4eb9deSJennifer Lee const std::vector<std::pair< 4751abe55efSEd Tanous std::string, std::vector<std::pair< 4761abe55efSEd Tanous std::string, std::vector<std::string>>>>> 4776c4eb9deSJennifer Lee &subtree) { 4781abe55efSEd Tanous if (ec) 4791abe55efSEd Tanous { 480f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4816c4eb9deSJennifer Lee return; 482729dae72SJennifer Lee } 483c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 484c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 4856c4eb9deSJennifer Lee 4861abe55efSEd Tanous for (auto &obj : subtree) 4871abe55efSEd Tanous { 4881abe55efSEd Tanous const std::vector< 4891abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 4906c4eb9deSJennifer Lee &connections = obj.second; 4916c4eb9deSJennifer Lee 492f4b65ab1SJennifer Lee // if can't parse fw id then return 49327826b5fSEd Tanous std::size_t idPos; 49427826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 495f4b65ab1SJennifer Lee { 496f12894f8SJason M. Bills messages::internalError(asyncResp->res); 497f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 498f4b65ab1SJennifer Lee return; 499f4b65ab1SJennifer Lee } 500f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 501f4b65ab1SJennifer Lee 5021abe55efSEd Tanous for (auto &conn : connections) 5031abe55efSEd Tanous { 504c711bf86SEd Tanous const std::string &connectionName = conn.first; 5051abe55efSEd Tanous BMCWEB_LOG_DEBUG << "connectionName = " 5061abe55efSEd Tanous << connectionName; 50755c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 5086c4eb9deSJennifer Lee 50955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 510f4b65ab1SJennifer Lee [asyncResp, 511f4b65ab1SJennifer Lee swId](const boost::system::error_code error_code, 512c711bf86SEd Tanous const VariantType &activation) { 5131abe55efSEd Tanous BMCWEB_LOG_DEBUG 5141abe55efSEd Tanous << "safe returned in lambda function"; 5151abe55efSEd Tanous if (error_code) 5161abe55efSEd Tanous { 517f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5186c4eb9deSJennifer Lee return; 5196c4eb9deSJennifer Lee } 520c711bf86SEd Tanous 521f4b65ab1SJennifer Lee const std::string *swActivationStatus = 522abf2add6SEd Tanous std::get_if<std::string>(&activation); 523f4b65ab1SJennifer Lee if (swActivationStatus == nullptr) 5241abe55efSEd Tanous { 525f12894f8SJason M. Bills messages::internalError(asyncResp->res); 526acb7cfb4SJennifer Lee return; 527acb7cfb4SJennifer Lee } 528f4b65ab1SJennifer Lee if (swActivationStatus != nullptr && 529f4b65ab1SJennifer Lee *swActivationStatus != 530f4b65ab1SJennifer Lee "xyz.openbmc_project.Software." 531f4b65ab1SJennifer Lee "Activation." 532f4b65ab1SJennifer Lee "Activations.Active") 5331abe55efSEd Tanous { 534f4b65ab1SJennifer Lee // The activation status of this software is 535f4b65ab1SJennifer Lee // not currently active, so does not need to 536f4b65ab1SJennifer Lee // be listed in the response 537c711bf86SEd Tanous return; 538c711bf86SEd Tanous } 539c711bf86SEd Tanous nlohmann::json &members = 540c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 541c711bf86SEd Tanous members.push_back( 542f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 5431abe55efSEd Tanous "FirmwareInventory/" + 544f4b65ab1SJennifer Lee swId}}); 5451abe55efSEd Tanous asyncResp->res 5461abe55efSEd Tanous .jsonValue["Members@odata.count"] = 547c711bf86SEd Tanous members.size(); 5486c4eb9deSJennifer Lee }, 5491abe55efSEd Tanous connectionName, obj.first, 5501abe55efSEd Tanous "org.freedesktop.DBus.Properties", "Get", 5511abe55efSEd Tanous "xyz.openbmc_project.Software.Activation", 552acb7cfb4SJennifer Lee "Activation"); 5536c4eb9deSJennifer Lee } 5546c4eb9deSJennifer Lee } 555c711bf86SEd Tanous }, 556c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 557c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 558c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 559c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 5601abe55efSEd Tanous std::array<const char *, 1>{ 5611abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 562729dae72SJennifer Lee } 563729dae72SJennifer Lee }; 564c711bf86SEd Tanous 5651abe55efSEd Tanous class SoftwareInventory : public Node 5661abe55efSEd Tanous { 567729dae72SJennifer Lee public: 568729dae72SJennifer Lee template <typename CrowApp> 5691abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 5701abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 5711abe55efSEd Tanous std::string()) 5721abe55efSEd Tanous { 573729dae72SJennifer Lee entityPrivileges = { 574729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 575729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 576729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 577729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 578729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 579729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 580729dae72SJennifer Lee } 581729dae72SJennifer Lee 582729dae72SJennifer Lee private: 58387d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 58487d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 58587d84729SAndrew Geissler const std::string &purpose) 58687d84729SAndrew Geissler { 58787d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 58887d84729SAndrew Geissler { 58987d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 59087d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 59187d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 59287d84729SAndrew Geissler } 59387d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 59487d84729SAndrew Geissler { 59587d84729SAndrew Geissler // TODO(geissonator) Need BIOS schema support added for this 59687d84729SAndrew Geissler // to be valid 59787d84729SAndrew Geissler // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 59887d84729SAndrew Geissler // members.push_back( 59987d84729SAndrew Geissler // {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}}); 60087d84729SAndrew Geissler // aResp->res.jsonValue["Members@odata.count"] = members.size(); 60187d84729SAndrew Geissler } 60287d84729SAndrew Geissler else 60387d84729SAndrew Geissler { 60487d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 60587d84729SAndrew Geissler } 60687d84729SAndrew Geissler } 60787d84729SAndrew Geissler 60855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 6091abe55efSEd Tanous const std::vector<std::string> ¶ms) override 6101abe55efSEd Tanous { 611c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 6120f74e643SEd Tanous res.jsonValue["@odata.type"] = 6130f74e643SEd Tanous "#SoftwareInventory.v1_1_0.SoftwareInventory"; 6140f74e643SEd Tanous res.jsonValue["@odata.context"] = 6150f74e643SEd Tanous "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 6160f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory"; 6170f74e643SEd Tanous res.jsonValue["Updateable"] = false; 6180f74e643SEd Tanous res.jsonValue["Status"]["Health"] = "OK"; 6190f74e643SEd Tanous res.jsonValue["Status"]["HealthRollup"] = "OK"; 6200f74e643SEd Tanous res.jsonValue["Status"]["State"] = "Enabled"; 6216c4eb9deSJennifer Lee 6221abe55efSEd Tanous if (params.size() != 1) 6231abe55efSEd Tanous { 624f12894f8SJason M. Bills messages::internalError(res); 625729dae72SJennifer Lee res.end(); 626729dae72SJennifer Lee return; 627729dae72SJennifer Lee } 628729dae72SJennifer Lee 6293ae837c9SEd Tanous std::shared_ptr<std::string> swId = 630c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 631c711bf86SEd Tanous 63255c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 6333ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 634c711bf86SEd Tanous 635c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 6363ae837c9SEd Tanous [asyncResp, swId]( 637c711bf86SEd Tanous const boost::system::error_code ec, 6386c4eb9deSJennifer Lee const std::vector<std::pair< 6391abe55efSEd Tanous std::string, std::vector<std::pair< 6401abe55efSEd Tanous std::string, std::vector<std::string>>>>> 6416c4eb9deSJennifer Lee &subtree) { 64255c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 6431abe55efSEd Tanous if (ec) 6441abe55efSEd Tanous { 645f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6466c4eb9deSJennifer Lee return; 6476c4eb9deSJennifer Lee } 6486c4eb9deSJennifer Lee 6491abe55efSEd Tanous for (const std::pair< 6501abe55efSEd Tanous std::string, 6511abe55efSEd Tanous std::vector< 6521abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 6531abe55efSEd Tanous &obj : subtree) 6541abe55efSEd Tanous { 6553ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 6561abe55efSEd Tanous { 657acb7cfb4SJennifer Lee continue; 658acb7cfb4SJennifer Lee } 659acb7cfb4SJennifer Lee 660f4b65ab1SJennifer Lee if (obj.second.size() < 1) 6611abe55efSEd Tanous { 662acb7cfb4SJennifer Lee continue; 663acb7cfb4SJennifer Lee } 6646c4eb9deSJennifer Lee 66555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 6661abe55efSEd Tanous [asyncResp, 6673ae837c9SEd Tanous swId](const boost::system::error_code error_code, 6681abe55efSEd Tanous const boost::container::flat_map< 6691abe55efSEd Tanous std::string, VariantType> &propertiesList) { 6701abe55efSEd Tanous if (error_code) 6711abe55efSEd Tanous { 672f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6736c4eb9deSJennifer Lee return; 6746c4eb9deSJennifer Lee } 6751abe55efSEd Tanous boost::container::flat_map< 6761abe55efSEd Tanous std::string, VariantType>::const_iterator it = 6776c4eb9deSJennifer Lee propertiesList.find("Purpose"); 6781abe55efSEd Tanous if (it == propertiesList.end()) 6791abe55efSEd Tanous { 6801abe55efSEd Tanous BMCWEB_LOG_DEBUG 6811abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 682f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 683f12894f8SJason M. Bills "Purpose"); 6846c4eb9deSJennifer Lee return; 6856c4eb9deSJennifer Lee } 6863ae837c9SEd Tanous const std::string *swInvPurpose = 687abf2add6SEd Tanous std::get_if<std::string>(&it->second); 6883ae837c9SEd Tanous if (swInvPurpose == nullptr) 6891abe55efSEd Tanous { 6901abe55efSEd Tanous BMCWEB_LOG_DEBUG 6911abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 692f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 693f12894f8SJason M. Bills "", "Purpose"); 694acb7cfb4SJennifer Lee return; 695acb7cfb4SJennifer Lee } 696c711bf86SEd Tanous 6973ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 6983ae837c9SEd Tanous << *swInvPurpose; 699c711bf86SEd Tanous it = propertiesList.find("Version"); 7001abe55efSEd Tanous if (it == propertiesList.end()) 7011abe55efSEd Tanous { 7021abe55efSEd Tanous BMCWEB_LOG_DEBUG 7031abe55efSEd Tanous << "Can't find property \"Version\"!"; 704f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 705f12894f8SJason M. Bills "Version"); 706c711bf86SEd Tanous return; 707acb7cfb4SJennifer Lee } 708acb7cfb4SJennifer Lee 709f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 710c711bf86SEd Tanous 711f4b65ab1SJennifer Lee const std::string *version = 712abf2add6SEd Tanous std::get_if<std::string>(&it->second); 713f4b65ab1SJennifer Lee 714f4b65ab1SJennifer Lee if (version == nullptr) 7151abe55efSEd Tanous { 7161abe55efSEd Tanous BMCWEB_LOG_DEBUG 7171abe55efSEd Tanous << "Can't find property \"Version\"!"; 718f12894f8SJason M. Bills 719f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 720f12894f8SJason M. Bills "", "Version"); 7216c4eb9deSJennifer Lee return; 7226c4eb9deSJennifer Lee } 723c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 7243ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 72554daabe7SAndrew Geissler 72654daabe7SAndrew Geissler // swInvPurpose is of format: 72754daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 72854daabe7SAndrew Geissler // Translate this to "ABC update" 72954daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 73054daabe7SAndrew Geissler if (endDesc == std::string::npos) 73154daabe7SAndrew Geissler { 73254daabe7SAndrew Geissler messages::internalError(asyncResp->res); 73354daabe7SAndrew Geissler return; 73454daabe7SAndrew Geissler } 73554daabe7SAndrew Geissler endDesc++; 73654daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 73754daabe7SAndrew Geissler { 73854daabe7SAndrew Geissler messages::internalError(asyncResp->res); 73954daabe7SAndrew Geissler return; 74054daabe7SAndrew Geissler } 74154daabe7SAndrew Geissler 74254daabe7SAndrew Geissler std::string formatDesc = 74354daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 74454daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 74554daabe7SAndrew Geissler formatDesc + " update"; 74687d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 7476c4eb9deSJennifer Lee }, 748c711bf86SEd Tanous obj.second[0].first, obj.first, 749c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 750c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 7516c4eb9deSJennifer Lee } 752c711bf86SEd Tanous }, 753c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 754c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 755c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 756c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 7571abe55efSEd Tanous std::array<const char *, 1>{ 7581abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 7596c4eb9deSJennifer Lee } 760729dae72SJennifer Lee }; 761729dae72SJennifer Lee 762729dae72SJennifer Lee } // namespace redfish 763