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 27*0e7de46fSAndrew Geissler // Match signals added on software path 28acb7cfb4SJennifer Lee static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher; 29*0e7de46fSAndrew Geissler // Only allow one update at a time 30*0e7de46fSAndrew Geissler static bool fwUpdateInProgress = false; 31729dae72SJennifer Lee 321abe55efSEd Tanous class UpdateService : public Node 331abe55efSEd Tanous { 34729dae72SJennifer Lee public: 351abe55efSEd Tanous UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") 361abe55efSEd Tanous { 37729dae72SJennifer Lee entityPrivileges = { 38729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 39729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 40729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 41729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 42729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 43729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 44729dae72SJennifer Lee } 45729dae72SJennifer Lee 46729dae72SJennifer Lee private: 4755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 481abe55efSEd Tanous const std::vector<std::string> ¶ms) override 491abe55efSEd Tanous { 500f74e643SEd Tanous res.jsonValue["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 510f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/UpdateService"; 520f74e643SEd Tanous res.jsonValue["@odata.context"] = 530f74e643SEd Tanous "/redfish/v1/$metadata#UpdateService.UpdateService"; 540f74e643SEd Tanous res.jsonValue["Id"] = "UpdateService"; 550f74e643SEd Tanous res.jsonValue["Description"] = "Service for Software Update"; 560f74e643SEd Tanous res.jsonValue["Name"] = "Update Service"; 570f74e643SEd Tanous res.jsonValue["HttpPushUri"] = "/redfish/v1/UpdateService"; 580f74e643SEd Tanous // UpdateService cannot be disabled 590f74e643SEd Tanous res.jsonValue["ServiceEnabled"] = true; 600f74e643SEd Tanous res.jsonValue["FirmwareInventory"] = { 610f74e643SEd Tanous {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}}; 62729dae72SJennifer Lee res.end(); 63729dae72SJennifer Lee } 64*0e7de46fSAndrew Geissler static void cleanUp() 651abe55efSEd Tanous { 66*0e7de46fSAndrew Geissler fwUpdateInProgress = false; 67*0e7de46fSAndrew Geissler fwUpdateMatcher = nullptr; 68*0e7de46fSAndrew Geissler } 69*0e7de46fSAndrew Geissler static void activateImage(const std::string &objPath, 70*0e7de46fSAndrew Geissler const std::string &service) 71*0e7de46fSAndrew Geissler { 72*0e7de46fSAndrew Geissler BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; 73acb7cfb4SJennifer Lee crow::connections::systemBus->async_method_call( 74*0e7de46fSAndrew Geissler [](const boost::system::error_code error_code) { 751abe55efSEd Tanous if (error_code) 761abe55efSEd Tanous { 77acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "error_code = " << error_code; 78acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); 79acb7cfb4SJennifer Lee } 80acb7cfb4SJennifer Lee }, 81*0e7de46fSAndrew Geissler service, objPath, "org.freedesktop.DBus.Properties", "Set", 82acb7cfb4SJennifer Lee "xyz.openbmc_project.Software.Activation", "RequestedActivation", 83abf2add6SEd Tanous std::variant<std::string>( 84acb7cfb4SJennifer Lee "xyz.openbmc_project.Software.Activation.RequestedActivations." 85acb7cfb4SJennifer Lee "Active")); 86acb7cfb4SJennifer Lee } 87*0e7de46fSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 88*0e7de46fSAndrew Geissler boost::asio::deadline_timer &timeout, 89*0e7de46fSAndrew Geissler sdbusplus::message::message &m) 90*0e7de46fSAndrew Geissler { 91*0e7de46fSAndrew Geissler std::vector<std::pair< 92*0e7de46fSAndrew Geissler std::string, 93*0e7de46fSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 94*0e7de46fSAndrew Geissler interfacesProperties; 95*0e7de46fSAndrew Geissler 96*0e7de46fSAndrew Geissler sdbusplus::message::object_path objPath; 97*0e7de46fSAndrew Geissler 98*0e7de46fSAndrew Geissler m.read(objPath, interfacesProperties); 99*0e7de46fSAndrew Geissler 100*0e7de46fSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 101*0e7de46fSAndrew Geissler for (auto &interface : interfacesProperties) 102*0e7de46fSAndrew Geissler { 103*0e7de46fSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 104*0e7de46fSAndrew Geissler 105*0e7de46fSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 106*0e7de46fSAndrew Geissler { 107*0e7de46fSAndrew Geissler // Found our interface, disable callbacks 108*0e7de46fSAndrew Geissler fwUpdateMatcher = nullptr; 109*0e7de46fSAndrew Geissler 110*0e7de46fSAndrew Geissler // Retrieve service and activate 111*0e7de46fSAndrew Geissler crow::connections::systemBus->async_method_call( 112*0e7de46fSAndrew Geissler [objPath, asyncResp, &timeout]( 113*0e7de46fSAndrew Geissler const boost::system::error_code error_code, 114*0e7de46fSAndrew Geissler const std::vector<std::pair< 115*0e7de46fSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 116*0e7de46fSAndrew Geissler if (error_code) 117*0e7de46fSAndrew Geissler { 118*0e7de46fSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 119*0e7de46fSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 120*0e7de46fSAndrew Geissler << error_code.message(); 121*0e7de46fSAndrew Geissler messages::internalError(asyncResp->res); 122*0e7de46fSAndrew Geissler cleanUp(); 123*0e7de46fSAndrew Geissler return; 124*0e7de46fSAndrew Geissler } 125*0e7de46fSAndrew Geissler // Ensure we only got one service back 126*0e7de46fSAndrew Geissler if (objInfo.size() != 1) 127*0e7de46fSAndrew Geissler { 128*0e7de46fSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 129*0e7de46fSAndrew Geissler << objInfo.size(); 130*0e7de46fSAndrew Geissler messages::internalError(asyncResp->res); 131*0e7de46fSAndrew Geissler cleanUp(); 132*0e7de46fSAndrew Geissler return; 133*0e7de46fSAndrew Geissler } 134*0e7de46fSAndrew Geissler // cancel timer only when 135*0e7de46fSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 136*0e7de46fSAndrew Geissler // is added 137*0e7de46fSAndrew Geissler boost::system::error_code ec; 138*0e7de46fSAndrew Geissler timeout.cancel(ec); 139*0e7de46fSAndrew Geissler if (ec) 140*0e7de46fSAndrew Geissler { 141*0e7de46fSAndrew Geissler BMCWEB_LOG_ERROR << "error canceling timer " << ec; 142*0e7de46fSAndrew Geissler } 143*0e7de46fSAndrew Geissler UpdateService::activateImage(objPath.str, 144*0e7de46fSAndrew Geissler objInfo[0].first); 145*0e7de46fSAndrew Geissler redfish::messages::success(asyncResp->res); 146*0e7de46fSAndrew Geissler fwUpdateInProgress = false; 147*0e7de46fSAndrew Geissler }, 148*0e7de46fSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 149*0e7de46fSAndrew Geissler "/xyz/openbmc_project/object_mapper", 150*0e7de46fSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", 151*0e7de46fSAndrew Geissler objPath.str, 152*0e7de46fSAndrew Geissler std::array<const char *, 1>{ 153*0e7de46fSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 154*0e7de46fSAndrew Geissler } 155*0e7de46fSAndrew Geissler } 156*0e7de46fSAndrew Geissler } 157acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 1581abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1591abe55efSEd Tanous { 160acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 161acb7cfb4SJennifer Lee 162acb7cfb4SJennifer Lee // Only allow one FW update at a time 163*0e7de46fSAndrew Geissler if (fwUpdateInProgress != false) 1641abe55efSEd Tanous { 165acb7cfb4SJennifer Lee res.addHeader("Retry-After", "30"); 166*0e7de46fSAndrew Geissler messages::serviceTemporarilyUnavailable(res, "30"); 167acb7cfb4SJennifer Lee res.end(); 168acb7cfb4SJennifer Lee return; 169acb7cfb4SJennifer Lee } 170*0e7de46fSAndrew Geissler 171acb7cfb4SJennifer Lee // Make this const static so it survives outside this method 1721abe55efSEd Tanous static boost::asio::deadline_timer timeout( 1731abe55efSEd Tanous *req.ioService, boost::posix_time::seconds(5)); 174acb7cfb4SJennifer Lee 175acb7cfb4SJennifer Lee timeout.expires_from_now(boost::posix_time::seconds(5)); 176acb7cfb4SJennifer Lee 177acb7cfb4SJennifer Lee timeout.async_wait([&res](const boost::system::error_code &ec) { 178*0e7de46fSAndrew Geissler cleanUp(); 1791abe55efSEd Tanous if (ec == boost::asio::error::operation_aborted) 1801abe55efSEd Tanous { 181acb7cfb4SJennifer Lee // expected, we were canceled before the timer completed. 182acb7cfb4SJennifer Lee return; 183acb7cfb4SJennifer Lee } 1841abe55efSEd Tanous BMCWEB_LOG_ERROR 1851abe55efSEd Tanous << "Timed out waiting for firmware object being created"; 1861abe55efSEd Tanous BMCWEB_LOG_ERROR 1871abe55efSEd Tanous << "FW image may has already been uploaded to server"; 1881abe55efSEd Tanous if (ec) 1891abe55efSEd Tanous { 190acb7cfb4SJennifer Lee BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 191acb7cfb4SJennifer Lee return; 192acb7cfb4SJennifer Lee } 193acb7cfb4SJennifer Lee 194f12894f8SJason M. Bills redfish::messages::internalError(res); 195acb7cfb4SJennifer Lee res.end(); 196acb7cfb4SJennifer Lee }); 197acb7cfb4SJennifer Lee 198*0e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 199*0e7de46fSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 200acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Match fired"; 201*0e7de46fSAndrew Geissler softwareInterfaceAdded(asyncResp, timeout, m); 202acb7cfb4SJennifer Lee }; 203acb7cfb4SJennifer Lee 204*0e7de46fSAndrew Geissler fwUpdateInProgress = true; 205*0e7de46fSAndrew Geissler 206acb7cfb4SJennifer Lee fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 207acb7cfb4SJennifer Lee *crow::connections::systemBus, 208acb7cfb4SJennifer Lee "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 209acb7cfb4SJennifer Lee "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 210acb7cfb4SJennifer Lee callback); 211acb7cfb4SJennifer Lee 212acb7cfb4SJennifer Lee std::string filepath( 213acb7cfb4SJennifer Lee "/tmp/images/" + 214acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 215acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 216acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 217acb7cfb4SJennifer Lee std::ofstream::trunc); 218acb7cfb4SJennifer Lee out << req.body; 219acb7cfb4SJennifer Lee out.close(); 220acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 221acb7cfb4SJennifer Lee } 222729dae72SJennifer Lee }; 223729dae72SJennifer Lee 2241abe55efSEd Tanous class SoftwareInventoryCollection : public Node 2251abe55efSEd Tanous { 226729dae72SJennifer Lee public: 227729dae72SJennifer Lee template <typename CrowApp> 2281abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 2291abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 2301abe55efSEd Tanous { 231729dae72SJennifer Lee entityPrivileges = { 232729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 233729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 234729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 235729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 236729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 237729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 238729dae72SJennifer Lee } 239729dae72SJennifer Lee 240729dae72SJennifer Lee private: 24155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 2421abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2431abe55efSEd Tanous { 244c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2450f74e643SEd Tanous res.jsonValue["@odata.type"] = 2460f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 2470f74e643SEd Tanous res.jsonValue["@odata.id"] = 2480f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 2490f74e643SEd Tanous res.jsonValue["@odata.context"] = 2500f74e643SEd Tanous "/redfish/v1/" 2510f74e643SEd Tanous "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 2520f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 253c711bf86SEd Tanous 254c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 255c711bf86SEd Tanous [asyncResp]( 256c711bf86SEd Tanous const boost::system::error_code ec, 2576c4eb9deSJennifer Lee const std::vector<std::pair< 2581abe55efSEd Tanous std::string, std::vector<std::pair< 2591abe55efSEd Tanous std::string, std::vector<std::string>>>>> 2606c4eb9deSJennifer Lee &subtree) { 2611abe55efSEd Tanous if (ec) 2621abe55efSEd Tanous { 263f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2646c4eb9deSJennifer Lee return; 265729dae72SJennifer Lee } 266c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 267c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 2686c4eb9deSJennifer Lee 2691abe55efSEd Tanous for (auto &obj : subtree) 2701abe55efSEd Tanous { 2711abe55efSEd Tanous const std::vector< 2721abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 2736c4eb9deSJennifer Lee &connections = obj.second; 2746c4eb9deSJennifer Lee 275f4b65ab1SJennifer Lee // if can't parse fw id then return 27627826b5fSEd Tanous std::size_t idPos; 27727826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 278f4b65ab1SJennifer Lee { 279f12894f8SJason M. Bills messages::internalError(asyncResp->res); 280f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 281f4b65ab1SJennifer Lee return; 282f4b65ab1SJennifer Lee } 283f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 284f4b65ab1SJennifer Lee 2851abe55efSEd Tanous for (auto &conn : connections) 2861abe55efSEd Tanous { 287c711bf86SEd Tanous const std::string &connectionName = conn.first; 2881abe55efSEd Tanous BMCWEB_LOG_DEBUG << "connectionName = " 2891abe55efSEd Tanous << connectionName; 29055c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 2916c4eb9deSJennifer Lee 29255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 293f4b65ab1SJennifer Lee [asyncResp, 294f4b65ab1SJennifer Lee swId](const boost::system::error_code error_code, 295c711bf86SEd Tanous const VariantType &activation) { 2961abe55efSEd Tanous BMCWEB_LOG_DEBUG 2971abe55efSEd Tanous << "safe returned in lambda function"; 2981abe55efSEd Tanous if (error_code) 2991abe55efSEd Tanous { 300f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3016c4eb9deSJennifer Lee return; 3026c4eb9deSJennifer Lee } 303c711bf86SEd Tanous 304f4b65ab1SJennifer Lee const std::string *swActivationStatus = 305abf2add6SEd Tanous std::get_if<std::string>(&activation); 306f4b65ab1SJennifer Lee if (swActivationStatus == nullptr) 3071abe55efSEd Tanous { 308f12894f8SJason M. Bills messages::internalError(asyncResp->res); 309acb7cfb4SJennifer Lee return; 310acb7cfb4SJennifer Lee } 311f4b65ab1SJennifer Lee if (swActivationStatus != nullptr && 312f4b65ab1SJennifer Lee *swActivationStatus != 313f4b65ab1SJennifer Lee "xyz.openbmc_project.Software." 314f4b65ab1SJennifer Lee "Activation." 315f4b65ab1SJennifer Lee "Activations.Active") 3161abe55efSEd Tanous { 317f4b65ab1SJennifer Lee // The activation status of this software is 318f4b65ab1SJennifer Lee // not currently active, so does not need to 319f4b65ab1SJennifer Lee // be listed in the response 320c711bf86SEd Tanous return; 321c711bf86SEd Tanous } 322c711bf86SEd Tanous nlohmann::json &members = 323c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 324c711bf86SEd Tanous members.push_back( 325f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 3261abe55efSEd Tanous "FirmwareInventory/" + 327f4b65ab1SJennifer Lee swId}}); 3281abe55efSEd Tanous asyncResp->res 3291abe55efSEd Tanous .jsonValue["Members@odata.count"] = 330c711bf86SEd Tanous members.size(); 3316c4eb9deSJennifer Lee }, 3321abe55efSEd Tanous connectionName, obj.first, 3331abe55efSEd Tanous "org.freedesktop.DBus.Properties", "Get", 3341abe55efSEd Tanous "xyz.openbmc_project.Software.Activation", 335acb7cfb4SJennifer Lee "Activation"); 3366c4eb9deSJennifer Lee } 3376c4eb9deSJennifer Lee } 338c711bf86SEd Tanous }, 339c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 340c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 341c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 342c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 3431abe55efSEd Tanous std::array<const char *, 1>{ 3441abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 345729dae72SJennifer Lee } 346729dae72SJennifer Lee }; 347c711bf86SEd Tanous 3481abe55efSEd Tanous class SoftwareInventory : public Node 3491abe55efSEd Tanous { 350729dae72SJennifer Lee public: 351729dae72SJennifer Lee template <typename CrowApp> 3521abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 3531abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 3541abe55efSEd Tanous std::string()) 3551abe55efSEd Tanous { 356729dae72SJennifer Lee entityPrivileges = { 357729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 358729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 359729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 360729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 361729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 362729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 363729dae72SJennifer Lee } 364729dae72SJennifer Lee 365729dae72SJennifer Lee private: 36687d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 36787d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 36887d84729SAndrew Geissler const std::string &purpose) 36987d84729SAndrew Geissler { 37087d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 37187d84729SAndrew Geissler { 37287d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 37387d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 37487d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 37587d84729SAndrew Geissler } 37687d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 37787d84729SAndrew Geissler { 37887d84729SAndrew Geissler // TODO(geissonator) Need BIOS schema support added for this 37987d84729SAndrew Geissler // to be valid 38087d84729SAndrew Geissler // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 38187d84729SAndrew Geissler // members.push_back( 38287d84729SAndrew Geissler // {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}}); 38387d84729SAndrew Geissler // aResp->res.jsonValue["Members@odata.count"] = members.size(); 38487d84729SAndrew Geissler } 38587d84729SAndrew Geissler else 38687d84729SAndrew Geissler { 38787d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 38887d84729SAndrew Geissler } 38987d84729SAndrew Geissler } 39087d84729SAndrew Geissler 39155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 3921abe55efSEd Tanous const std::vector<std::string> ¶ms) override 3931abe55efSEd Tanous { 394c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 3950f74e643SEd Tanous res.jsonValue["@odata.type"] = 3960f74e643SEd Tanous "#SoftwareInventory.v1_1_0.SoftwareInventory"; 3970f74e643SEd Tanous res.jsonValue["@odata.context"] = 3980f74e643SEd Tanous "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 3990f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory"; 4000f74e643SEd Tanous res.jsonValue["Updateable"] = false; 4010f74e643SEd Tanous res.jsonValue["Status"]["Health"] = "OK"; 4020f74e643SEd Tanous res.jsonValue["Status"]["HealthRollup"] = "OK"; 4030f74e643SEd Tanous res.jsonValue["Status"]["State"] = "Enabled"; 4046c4eb9deSJennifer Lee 4051abe55efSEd Tanous if (params.size() != 1) 4061abe55efSEd Tanous { 407f12894f8SJason M. Bills messages::internalError(res); 408729dae72SJennifer Lee res.end(); 409729dae72SJennifer Lee return; 410729dae72SJennifer Lee } 411729dae72SJennifer Lee 4123ae837c9SEd Tanous std::shared_ptr<std::string> swId = 413c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 414c711bf86SEd Tanous 41555c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 4163ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 417c711bf86SEd Tanous 418c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 4193ae837c9SEd Tanous [asyncResp, swId]( 420c711bf86SEd Tanous const boost::system::error_code ec, 4216c4eb9deSJennifer Lee const std::vector<std::pair< 4221abe55efSEd Tanous std::string, std::vector<std::pair< 4231abe55efSEd Tanous std::string, std::vector<std::string>>>>> 4246c4eb9deSJennifer Lee &subtree) { 42555c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 4261abe55efSEd Tanous if (ec) 4271abe55efSEd Tanous { 428f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4296c4eb9deSJennifer Lee return; 4306c4eb9deSJennifer Lee } 4316c4eb9deSJennifer Lee 4321abe55efSEd Tanous for (const std::pair< 4331abe55efSEd Tanous std::string, 4341abe55efSEd Tanous std::vector< 4351abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 4361abe55efSEd Tanous &obj : subtree) 4371abe55efSEd Tanous { 4383ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 4391abe55efSEd Tanous { 440acb7cfb4SJennifer Lee continue; 441acb7cfb4SJennifer Lee } 442acb7cfb4SJennifer Lee 443f4b65ab1SJennifer Lee if (obj.second.size() < 1) 4441abe55efSEd Tanous { 445acb7cfb4SJennifer Lee continue; 446acb7cfb4SJennifer Lee } 4476c4eb9deSJennifer Lee 44855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 4491abe55efSEd Tanous [asyncResp, 4503ae837c9SEd Tanous swId](const boost::system::error_code error_code, 4511abe55efSEd Tanous const boost::container::flat_map< 4521abe55efSEd Tanous std::string, VariantType> &propertiesList) { 4531abe55efSEd Tanous if (error_code) 4541abe55efSEd Tanous { 455f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4566c4eb9deSJennifer Lee return; 4576c4eb9deSJennifer Lee } 4581abe55efSEd Tanous boost::container::flat_map< 4591abe55efSEd Tanous std::string, VariantType>::const_iterator it = 4606c4eb9deSJennifer Lee propertiesList.find("Purpose"); 4611abe55efSEd Tanous if (it == propertiesList.end()) 4621abe55efSEd Tanous { 4631abe55efSEd Tanous BMCWEB_LOG_DEBUG 4641abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 465f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 466f12894f8SJason M. Bills "Purpose"); 4676c4eb9deSJennifer Lee return; 4686c4eb9deSJennifer Lee } 4693ae837c9SEd Tanous const std::string *swInvPurpose = 470abf2add6SEd Tanous std::get_if<std::string>(&it->second); 4713ae837c9SEd Tanous if (swInvPurpose == nullptr) 4721abe55efSEd Tanous { 4731abe55efSEd Tanous BMCWEB_LOG_DEBUG 4741abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 475f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 476f12894f8SJason M. Bills "", "Purpose"); 477acb7cfb4SJennifer Lee return; 478acb7cfb4SJennifer Lee } 479c711bf86SEd Tanous 4803ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 4813ae837c9SEd Tanous << *swInvPurpose; 482c711bf86SEd Tanous it = propertiesList.find("Version"); 4831abe55efSEd Tanous if (it == propertiesList.end()) 4841abe55efSEd Tanous { 4851abe55efSEd Tanous BMCWEB_LOG_DEBUG 4861abe55efSEd Tanous << "Can't find property \"Version\"!"; 487f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 488f12894f8SJason M. Bills "Version"); 489c711bf86SEd Tanous return; 490acb7cfb4SJennifer Lee } 491acb7cfb4SJennifer Lee 492f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 493c711bf86SEd Tanous 494f4b65ab1SJennifer Lee const std::string *version = 495abf2add6SEd Tanous std::get_if<std::string>(&it->second); 496f4b65ab1SJennifer Lee 497f4b65ab1SJennifer Lee if (version == nullptr) 4981abe55efSEd Tanous { 4991abe55efSEd Tanous BMCWEB_LOG_DEBUG 5001abe55efSEd Tanous << "Can't find property \"Version\"!"; 501f12894f8SJason M. Bills 502f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 503f12894f8SJason M. Bills "", "Version"); 5046c4eb9deSJennifer Lee return; 5056c4eb9deSJennifer Lee } 506c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 5073ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 50854daabe7SAndrew Geissler 50954daabe7SAndrew Geissler // swInvPurpose is of format: 51054daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 51154daabe7SAndrew Geissler // Translate this to "ABC update" 51254daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 51354daabe7SAndrew Geissler if (endDesc == std::string::npos) 51454daabe7SAndrew Geissler { 51554daabe7SAndrew Geissler messages::internalError(asyncResp->res); 51654daabe7SAndrew Geissler return; 51754daabe7SAndrew Geissler } 51854daabe7SAndrew Geissler endDesc++; 51954daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 52054daabe7SAndrew Geissler { 52154daabe7SAndrew Geissler messages::internalError(asyncResp->res); 52254daabe7SAndrew Geissler return; 52354daabe7SAndrew Geissler } 52454daabe7SAndrew Geissler 52554daabe7SAndrew Geissler std::string formatDesc = 52654daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 52754daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 52854daabe7SAndrew Geissler formatDesc + " update"; 52987d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 5306c4eb9deSJennifer Lee }, 531c711bf86SEd Tanous obj.second[0].first, obj.first, 532c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 533c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 5346c4eb9deSJennifer Lee } 535c711bf86SEd Tanous }, 536c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 537c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 538c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 539c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 5401abe55efSEd Tanous std::array<const char *, 1>{ 5411abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 5426c4eb9deSJennifer Lee } 543729dae72SJennifer Lee }; 544729dae72SJennifer Lee 545729dae72SJennifer Lee } // namespace redfish 546