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 } 5786adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 5886adcd6dSAndrew Geissler sdbusplus::message::message &m) 5986adcd6dSAndrew Geissler { 6086adcd6dSAndrew Geissler std::vector<std::pair< 6186adcd6dSAndrew Geissler std::string, 6286adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 6386adcd6dSAndrew Geissler interfacesProperties; 6486adcd6dSAndrew Geissler 6586adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 6686adcd6dSAndrew Geissler 6786adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 6886adcd6dSAndrew Geissler 6986adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 7086adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 7186adcd6dSAndrew Geissler { 7286adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 7386adcd6dSAndrew Geissler 7486adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 7586adcd6dSAndrew Geissler { 7686adcd6dSAndrew Geissler // Found our interface, disable callbacks 7786adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 7886adcd6dSAndrew Geissler 7986adcd6dSAndrew Geissler // Retrieve service and activate 8086adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 8186adcd6dSAndrew Geissler [objPath, asyncResp]( 8286adcd6dSAndrew Geissler const boost::system::error_code error_code, 8386adcd6dSAndrew Geissler const std::vector<std::pair< 8486adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 8586adcd6dSAndrew Geissler if (error_code) 8686adcd6dSAndrew Geissler { 8786adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 8886adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 8986adcd6dSAndrew Geissler << error_code.message(); 9086adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 9186adcd6dSAndrew Geissler cleanUp(); 9286adcd6dSAndrew Geissler return; 9386adcd6dSAndrew Geissler } 9486adcd6dSAndrew Geissler // Ensure we only got one service back 9586adcd6dSAndrew Geissler if (objInfo.size() != 1) 9686adcd6dSAndrew Geissler { 9786adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 9886adcd6dSAndrew Geissler << objInfo.size(); 9986adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 10086adcd6dSAndrew Geissler cleanUp(); 10186adcd6dSAndrew Geissler return; 10286adcd6dSAndrew Geissler } 10386adcd6dSAndrew Geissler // cancel timer only when 10486adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 10586adcd6dSAndrew Geissler // is added 10686adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 10786adcd6dSAndrew Geissler 10886adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 10986adcd6dSAndrew Geissler redfish::messages::success(asyncResp->res); 11086adcd6dSAndrew Geissler fwUpdateInProgress = false; 11186adcd6dSAndrew Geissler }, 11286adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 11386adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 11486adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 11586adcd6dSAndrew Geissler std::array<const char *, 1>{ 11686adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 11786adcd6dSAndrew Geissler } 11886adcd6dSAndrew Geissler } 11986adcd6dSAndrew Geissler } 12086adcd6dSAndrew Geissler 12186adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 12286adcd6dSAndrew Geissler const crow::Request &req) 12386adcd6dSAndrew Geissler { 12486adcd6dSAndrew Geissler // Only allow one FW update at a time 12586adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 12686adcd6dSAndrew Geissler { 12786adcd6dSAndrew Geissler asyncResp->res.addHeader("Retry-After", "30"); 12886adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 12986adcd6dSAndrew Geissler return; 13086adcd6dSAndrew Geissler } 13186adcd6dSAndrew Geissler 13286adcd6dSAndrew Geissler fwAvailableTimer = std::make_unique<boost::asio::deadline_timer>( 13386adcd6dSAndrew Geissler *req.ioService, boost::posix_time::seconds(5)); 13486adcd6dSAndrew Geissler 13586adcd6dSAndrew Geissler fwAvailableTimer->expires_from_now(boost::posix_time::seconds(5)); 13686adcd6dSAndrew Geissler 13786adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 13886adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 13986adcd6dSAndrew Geissler cleanUp(); 14086adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 14186adcd6dSAndrew Geissler { 14286adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 14386adcd6dSAndrew Geissler return; 14486adcd6dSAndrew Geissler } 14586adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 14686adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 14786adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 14886adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 14986adcd6dSAndrew Geissler if (ec) 15086adcd6dSAndrew Geissler { 15186adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 15286adcd6dSAndrew Geissler return; 15386adcd6dSAndrew Geissler } 15486adcd6dSAndrew Geissler 15586adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 15686adcd6dSAndrew Geissler }); 15786adcd6dSAndrew Geissler 15886adcd6dSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 15986adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 16086adcd6dSAndrew Geissler softwareInterfaceAdded(asyncResp, m); 16186adcd6dSAndrew Geissler }; 16286adcd6dSAndrew Geissler 16386adcd6dSAndrew Geissler fwUpdateInProgress = true; 16486adcd6dSAndrew Geissler 16586adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 16686adcd6dSAndrew Geissler *crow::connections::systemBus, 16786adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 16886adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 16986adcd6dSAndrew Geissler callback); 17086adcd6dSAndrew Geissler } 171729dae72SJennifer Lee 1721abe55efSEd Tanous class UpdateService : public Node 1731abe55efSEd Tanous { 174729dae72SJennifer Lee public: 1751abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 1761abe55efSEd Tanous { 177729dae72SJennifer Lee entityPrivileges = { 178729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 179729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 180729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 181729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 182729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 183729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 184729dae72SJennifer Lee } 185729dae72SJennifer Lee 186729dae72SJennifer Lee private: 18755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1881abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1891abe55efSEd Tanous { 1900f74e643SEd Tanous res.jsonValue["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 1910f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 1920f74e643SEd Tanous res.jsonValue["@odata.context"] = 1930f74e643SEd Tanous "/redfish/v1/$metadata#UpdateService.UpdateService"; 1940f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 1950f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 1960f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 1970f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 1980f74e643SEd Tanous // UpdateService cannot be disabled 1990f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 2000f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 2010f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 202729dae72SJennifer Lee res.end(); 203729dae72SJennifer Lee } 2040e7de46fSAndrew Geissler 205*fa1a5a38SJayashankar Padath void doPatch(crow::Response &res, const crow::Request &req, 206*fa1a5a38SJayashankar Padath const std::vector<std::string> ¶ms) override 207*fa1a5a38SJayashankar Padath { 208*fa1a5a38SJayashankar Padath BMCWEB_LOG_DEBUG << "doPatch..."; 209*fa1a5a38SJayashankar Padath 210*fa1a5a38SJayashankar Padath std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 211*fa1a5a38SJayashankar Padath std::string applyTime; 212*fa1a5a38SJayashankar Padath 213*fa1a5a38SJayashankar Padath if (!json_util::readJson(req, res, "ApplyTime", applyTime)) 214*fa1a5a38SJayashankar Padath { 215*fa1a5a38SJayashankar Padath return; 216*fa1a5a38SJayashankar Padath } 217*fa1a5a38SJayashankar Padath 218*fa1a5a38SJayashankar Padath if ((applyTime == "Immediate") || (applyTime == "OnReset")) 219*fa1a5a38SJayashankar Padath { 220*fa1a5a38SJayashankar Padath std::string applyTimeNewVal; 221*fa1a5a38SJayashankar Padath if (applyTime == "Immediate") 222*fa1a5a38SJayashankar Padath { 223*fa1a5a38SJayashankar Padath applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime." 224*fa1a5a38SJayashankar Padath "RequestedApplyTimes.Immediate"; 225*fa1a5a38SJayashankar Padath } 226*fa1a5a38SJayashankar Padath else 227*fa1a5a38SJayashankar Padath { 228*fa1a5a38SJayashankar Padath applyTimeNewVal = "xyz.openbmc_project.Software.ApplyTime." 229*fa1a5a38SJayashankar Padath "RequestedApplyTimes.OnReset"; 230*fa1a5a38SJayashankar Padath } 231*fa1a5a38SJayashankar Padath 232*fa1a5a38SJayashankar Padath // Set the requested image apply time value 233*fa1a5a38SJayashankar Padath crow::connections::systemBus->async_method_call( 234*fa1a5a38SJayashankar Padath [asyncResp](const boost::system::error_code ec) { 235*fa1a5a38SJayashankar Padath if (ec) 236*fa1a5a38SJayashankar Padath { 237*fa1a5a38SJayashankar Padath BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 238*fa1a5a38SJayashankar Padath messages::internalError(asyncResp->res); 239*fa1a5a38SJayashankar Padath return; 240*fa1a5a38SJayashankar Padath } 241*fa1a5a38SJayashankar Padath messages::success(asyncResp->res); 242*fa1a5a38SJayashankar Padath }, 243*fa1a5a38SJayashankar Padath "xyz.openbmc_project.Settings", 244*fa1a5a38SJayashankar Padath "/xyz/openbmc_project/software/apply_time", 245*fa1a5a38SJayashankar Padath "org.freedesktop.DBus.Properties", "Set", 246*fa1a5a38SJayashankar Padath "xyz.openbmc_project.Software.ApplyTime", "RequestedApplyTime", 247*fa1a5a38SJayashankar Padath std::variant<std::string>{applyTimeNewVal}); 248*fa1a5a38SJayashankar Padath } 249*fa1a5a38SJayashankar Padath else 250*fa1a5a38SJayashankar Padath { 251*fa1a5a38SJayashankar Padath BMCWEB_LOG_INFO << "ApplyTime value is not in the list of " 252*fa1a5a38SJayashankar Padath "acceptable values"; 253*fa1a5a38SJayashankar Padath messages::propertyValueNotInList(asyncResp->res, applyTime, 254*fa1a5a38SJayashankar Padath "ApplyTime"); 255*fa1a5a38SJayashankar Padath } 256*fa1a5a38SJayashankar Padath } 257*fa1a5a38SJayashankar Padath 258acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 2591abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2601abe55efSEd Tanous { 261acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 262acb7cfb4SJennifer Lee 2630e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 264acb7cfb4SJennifer Lee 26586adcd6dSAndrew Geissler // Setup callback for when new software detected 26686adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 267acb7cfb4SJennifer Lee 268acb7cfb4SJennifer Lee std::string filepath( 269acb7cfb4SJennifer Lee "/tmp/images/" + 270acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 271acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 272acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 273acb7cfb4SJennifer Lee std::ofstream::trunc); 274acb7cfb4SJennifer Lee out << req.body; 275acb7cfb4SJennifer Lee out.close(); 276acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 277acb7cfb4SJennifer Lee } 278729dae72SJennifer Lee }; 279729dae72SJennifer Lee 2801abe55efSEd Tanous class SoftwareInventoryCollection : public Node 2811abe55efSEd Tanous { 282729dae72SJennifer Lee public: 283729dae72SJennifer Lee template <typename CrowApp> 2841abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 2851abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 2861abe55efSEd Tanous { 287729dae72SJennifer Lee entityPrivileges = { 288729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 289729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 290729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 291729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 292729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 293729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 294729dae72SJennifer Lee } 295729dae72SJennifer Lee 296729dae72SJennifer Lee private: 29755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 2981abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2991abe55efSEd Tanous { 300c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 3010f74e643SEd Tanous res.jsonValue["@odata.type"] = 3020f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 3030f74e643SEd Tanous res.jsonValue["@odata.id"] = 3040f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 3050f74e643SEd Tanous res.jsonValue["@odata.context"] = 3060f74e643SEd Tanous "/redfish/v1/" 3070f74e643SEd Tanous "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 3080f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 309c711bf86SEd Tanous 310c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 311c711bf86SEd Tanous [asyncResp]( 312c711bf86SEd Tanous const boost::system::error_code ec, 3136c4eb9deSJennifer Lee const std::vector<std::pair< 3141abe55efSEd Tanous std::string, std::vector<std::pair< 3151abe55efSEd Tanous std::string, std::vector<std::string>>>>> 3166c4eb9deSJennifer Lee &subtree) { 3171abe55efSEd Tanous if (ec) 3181abe55efSEd Tanous { 319f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3206c4eb9deSJennifer Lee return; 321729dae72SJennifer Lee } 322c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 323c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 3246c4eb9deSJennifer Lee 3251abe55efSEd Tanous for (auto &obj : subtree) 3261abe55efSEd Tanous { 3271abe55efSEd Tanous const std::vector< 3281abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 3296c4eb9deSJennifer Lee &connections = obj.second; 3306c4eb9deSJennifer Lee 331f4b65ab1SJennifer Lee // if can't parse fw id then return 33227826b5fSEd Tanous std::size_t idPos; 33327826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 334f4b65ab1SJennifer Lee { 335f12894f8SJason M. Bills messages::internalError(asyncResp->res); 336f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 337f4b65ab1SJennifer Lee return; 338f4b65ab1SJennifer Lee } 339f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 340f4b65ab1SJennifer Lee 3411abe55efSEd Tanous for (auto &conn : connections) 3421abe55efSEd Tanous { 343c711bf86SEd Tanous const std::string &connectionName = conn.first; 3441abe55efSEd Tanous BMCWEB_LOG_DEBUG << "connectionName = " 3451abe55efSEd Tanous << connectionName; 34655c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 3476c4eb9deSJennifer Lee 34855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 349f4b65ab1SJennifer Lee [asyncResp, 350f4b65ab1SJennifer Lee swId](const boost::system::error_code error_code, 351c711bf86SEd Tanous const VariantType &activation) { 3521abe55efSEd Tanous BMCWEB_LOG_DEBUG 3531abe55efSEd Tanous << "safe returned in lambda function"; 3541abe55efSEd Tanous if (error_code) 3551abe55efSEd Tanous { 356f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3576c4eb9deSJennifer Lee return; 3586c4eb9deSJennifer Lee } 359c711bf86SEd Tanous 360f4b65ab1SJennifer Lee const std::string *swActivationStatus = 361abf2add6SEd Tanous std::get_if<std::string>(&activation); 362f4b65ab1SJennifer Lee if (swActivationStatus == nullptr) 3631abe55efSEd Tanous { 364f12894f8SJason M. Bills messages::internalError(asyncResp->res); 365acb7cfb4SJennifer Lee return; 366acb7cfb4SJennifer Lee } 367f4b65ab1SJennifer Lee if (swActivationStatus != nullptr && 368f4b65ab1SJennifer Lee *swActivationStatus != 369f4b65ab1SJennifer Lee "xyz.openbmc_project.Software." 370f4b65ab1SJennifer Lee "Activation." 371f4b65ab1SJennifer Lee "Activations.Active") 3721abe55efSEd Tanous { 373f4b65ab1SJennifer Lee // The activation status of this software is 374f4b65ab1SJennifer Lee // not currently active, so does not need to 375f4b65ab1SJennifer Lee // be listed in the response 376c711bf86SEd Tanous return; 377c711bf86SEd Tanous } 378c711bf86SEd Tanous nlohmann::json &members = 379c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 380c711bf86SEd Tanous members.push_back( 381f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 3821abe55efSEd Tanous "FirmwareInventory/" + 383f4b65ab1SJennifer Lee swId}}); 3841abe55efSEd Tanous asyncResp->res 3851abe55efSEd Tanous .jsonValue["Members@odata.count"] = 386c711bf86SEd Tanous members.size(); 3876c4eb9deSJennifer Lee }, 3881abe55efSEd Tanous connectionName, obj.first, 3891abe55efSEd Tanous "org.freedesktop.DBus.Properties", "Get", 3901abe55efSEd Tanous "xyz.openbmc_project.Software.Activation", 391acb7cfb4SJennifer Lee "Activation"); 3926c4eb9deSJennifer Lee } 3936c4eb9deSJennifer Lee } 394c711bf86SEd Tanous }, 395c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 396c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 397c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 398c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 3991abe55efSEd Tanous std::array<const char *, 1>{ 4001abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 401729dae72SJennifer Lee } 402729dae72SJennifer Lee }; 403c711bf86SEd Tanous 4041abe55efSEd Tanous class SoftwareInventory : public Node 4051abe55efSEd Tanous { 406729dae72SJennifer Lee public: 407729dae72SJennifer Lee template <typename CrowApp> 4081abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 4091abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 4101abe55efSEd Tanous std::string()) 4111abe55efSEd Tanous { 412729dae72SJennifer Lee entityPrivileges = { 413729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 414729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 415729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 416729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 417729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 418729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 419729dae72SJennifer Lee } 420729dae72SJennifer Lee 421729dae72SJennifer Lee private: 42287d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 42387d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 42487d84729SAndrew Geissler const std::string &purpose) 42587d84729SAndrew Geissler { 42687d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 42787d84729SAndrew Geissler { 42887d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 42987d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 43087d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 43187d84729SAndrew Geissler } 43287d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 43387d84729SAndrew Geissler { 43487d84729SAndrew Geissler // TODO(geissonator) Need BIOS schema support added for this 43587d84729SAndrew Geissler // to be valid 43687d84729SAndrew Geissler // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 43787d84729SAndrew Geissler // members.push_back( 43887d84729SAndrew Geissler // {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}}); 43987d84729SAndrew Geissler // aResp->res.jsonValue["Members@odata.count"] = members.size(); 44087d84729SAndrew Geissler } 44187d84729SAndrew Geissler else 44287d84729SAndrew Geissler { 44387d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 44487d84729SAndrew Geissler } 44587d84729SAndrew Geissler } 44687d84729SAndrew Geissler 44755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 4481abe55efSEd Tanous const std::vector<std::string> ¶ms) override 4491abe55efSEd Tanous { 450c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 4510f74e643SEd Tanous res.jsonValue["@odata.type"] = 4520f74e643SEd Tanous "#SoftwareInventory.v1_1_0.SoftwareInventory"; 4530f74e643SEd Tanous res.jsonValue["@odata.context"] = 4540f74e643SEd Tanous "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 4550f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory"; 4560f74e643SEd Tanous res.jsonValue["Updateable"] = false; 4570f74e643SEd Tanous res.jsonValue["Status"]["Health"] = "OK"; 4580f74e643SEd Tanous res.jsonValue["Status"]["HealthRollup"] = "OK"; 4590f74e643SEd Tanous res.jsonValue["Status"]["State"] = "Enabled"; 4606c4eb9deSJennifer Lee 4611abe55efSEd Tanous if (params.size() != 1) 4621abe55efSEd Tanous { 463f12894f8SJason M. Bills messages::internalError(res); 464729dae72SJennifer Lee res.end(); 465729dae72SJennifer Lee return; 466729dae72SJennifer Lee } 467729dae72SJennifer Lee 4683ae837c9SEd Tanous std::shared_ptr<std::string> swId = 469c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 470c711bf86SEd Tanous 47155c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 4723ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 473c711bf86SEd Tanous 474c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 4753ae837c9SEd Tanous [asyncResp, swId]( 476c711bf86SEd Tanous const boost::system::error_code ec, 4776c4eb9deSJennifer Lee const std::vector<std::pair< 4781abe55efSEd Tanous std::string, std::vector<std::pair< 4791abe55efSEd Tanous std::string, std::vector<std::string>>>>> 4806c4eb9deSJennifer Lee &subtree) { 48155c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 4821abe55efSEd Tanous if (ec) 4831abe55efSEd Tanous { 484f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4856c4eb9deSJennifer Lee return; 4866c4eb9deSJennifer Lee } 4876c4eb9deSJennifer Lee 4881abe55efSEd Tanous for (const std::pair< 4891abe55efSEd Tanous std::string, 4901abe55efSEd Tanous std::vector< 4911abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 4921abe55efSEd Tanous &obj : subtree) 4931abe55efSEd Tanous { 4943ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 4951abe55efSEd Tanous { 496acb7cfb4SJennifer Lee continue; 497acb7cfb4SJennifer Lee } 498acb7cfb4SJennifer Lee 499f4b65ab1SJennifer Lee if (obj.second.size() < 1) 5001abe55efSEd Tanous { 501acb7cfb4SJennifer Lee continue; 502acb7cfb4SJennifer Lee } 5036c4eb9deSJennifer Lee 50455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 5051abe55efSEd Tanous [asyncResp, 5063ae837c9SEd Tanous swId](const boost::system::error_code error_code, 5071abe55efSEd Tanous const boost::container::flat_map< 5081abe55efSEd Tanous std::string, VariantType> &propertiesList) { 5091abe55efSEd Tanous if (error_code) 5101abe55efSEd Tanous { 511f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5126c4eb9deSJennifer Lee return; 5136c4eb9deSJennifer Lee } 5141abe55efSEd Tanous boost::container::flat_map< 5151abe55efSEd Tanous std::string, VariantType>::const_iterator it = 5166c4eb9deSJennifer Lee propertiesList.find("Purpose"); 5171abe55efSEd Tanous if (it == propertiesList.end()) 5181abe55efSEd Tanous { 5191abe55efSEd Tanous BMCWEB_LOG_DEBUG 5201abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 521f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 522f12894f8SJason M. Bills "Purpose"); 5236c4eb9deSJennifer Lee return; 5246c4eb9deSJennifer Lee } 5253ae837c9SEd Tanous const std::string *swInvPurpose = 526abf2add6SEd Tanous std::get_if<std::string>(&it->second); 5273ae837c9SEd Tanous if (swInvPurpose == nullptr) 5281abe55efSEd Tanous { 5291abe55efSEd Tanous BMCWEB_LOG_DEBUG 5301abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 531f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 532f12894f8SJason M. Bills "", "Purpose"); 533acb7cfb4SJennifer Lee return; 534acb7cfb4SJennifer Lee } 535c711bf86SEd Tanous 5363ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 5373ae837c9SEd Tanous << *swInvPurpose; 538c711bf86SEd Tanous it = propertiesList.find("Version"); 5391abe55efSEd Tanous if (it == propertiesList.end()) 5401abe55efSEd Tanous { 5411abe55efSEd Tanous BMCWEB_LOG_DEBUG 5421abe55efSEd Tanous << "Can't find property \"Version\"!"; 543f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 544f12894f8SJason M. Bills "Version"); 545c711bf86SEd Tanous return; 546acb7cfb4SJennifer Lee } 547acb7cfb4SJennifer Lee 548f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 549c711bf86SEd Tanous 550f4b65ab1SJennifer Lee const std::string *version = 551abf2add6SEd Tanous std::get_if<std::string>(&it->second); 552f4b65ab1SJennifer Lee 553f4b65ab1SJennifer Lee if (version == nullptr) 5541abe55efSEd Tanous { 5551abe55efSEd Tanous BMCWEB_LOG_DEBUG 5561abe55efSEd Tanous << "Can't find property \"Version\"!"; 557f12894f8SJason M. Bills 558f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 559f12894f8SJason M. Bills "", "Version"); 5606c4eb9deSJennifer Lee return; 5616c4eb9deSJennifer Lee } 562c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 5633ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 56454daabe7SAndrew Geissler 56554daabe7SAndrew Geissler // swInvPurpose is of format: 56654daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 56754daabe7SAndrew Geissler // Translate this to "ABC update" 56854daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 56954daabe7SAndrew Geissler if (endDesc == std::string::npos) 57054daabe7SAndrew Geissler { 57154daabe7SAndrew Geissler messages::internalError(asyncResp->res); 57254daabe7SAndrew Geissler return; 57354daabe7SAndrew Geissler } 57454daabe7SAndrew Geissler endDesc++; 57554daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 57654daabe7SAndrew Geissler { 57754daabe7SAndrew Geissler messages::internalError(asyncResp->res); 57854daabe7SAndrew Geissler return; 57954daabe7SAndrew Geissler } 58054daabe7SAndrew Geissler 58154daabe7SAndrew Geissler std::string formatDesc = 58254daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 58354daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 58454daabe7SAndrew Geissler formatDesc + " update"; 58587d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 5866c4eb9deSJennifer Lee }, 587c711bf86SEd Tanous obj.second[0].first, obj.first, 588c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 589c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 5906c4eb9deSJennifer Lee } 591c711bf86SEd Tanous }, 592c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 593c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 594c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 595c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 5961abe55efSEd Tanous std::array<const char *, 1>{ 5971abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 5986c4eb9deSJennifer Lee } 599729dae72SJennifer Lee }; 600729dae72SJennifer Lee 601729dae72SJennifer Lee } // namespace redfish 602