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; 31*86adcd6dSAndrew Geissler // Timer for software available 32*86adcd6dSAndrew Geissler static std::unique_ptr<boost::asio::deadline_timer> fwAvailableTimer; 33*86adcd6dSAndrew Geissler 34*86adcd6dSAndrew Geissler static void cleanUp() 35*86adcd6dSAndrew Geissler { 36*86adcd6dSAndrew Geissler fwUpdateInProgress = false; 37*86adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 38*86adcd6dSAndrew Geissler } 39*86adcd6dSAndrew Geissler static void activateImage(const std::string &objPath, 40*86adcd6dSAndrew Geissler const std::string &service) 41*86adcd6dSAndrew Geissler { 42*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Activate image for " << objPath << " " << service; 43*86adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 44*86adcd6dSAndrew Geissler [](const boost::system::error_code error_code) { 45*86adcd6dSAndrew Geissler if (error_code) 46*86adcd6dSAndrew Geissler { 47*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 48*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " << error_code.message(); 49*86adcd6dSAndrew Geissler } 50*86adcd6dSAndrew Geissler }, 51*86adcd6dSAndrew Geissler service, objPath, "org.freedesktop.DBus.Properties", "Set", 52*86adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation", "RequestedActivation", 53*86adcd6dSAndrew Geissler std::variant<std::string>( 54*86adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation.RequestedActivations." 55*86adcd6dSAndrew Geissler "Active")); 56*86adcd6dSAndrew Geissler } 57*86adcd6dSAndrew Geissler static void softwareInterfaceAdded(std::shared_ptr<AsyncResp> asyncResp, 58*86adcd6dSAndrew Geissler sdbusplus::message::message &m) 59*86adcd6dSAndrew Geissler { 60*86adcd6dSAndrew Geissler std::vector<std::pair< 61*86adcd6dSAndrew Geissler std::string, 62*86adcd6dSAndrew Geissler std::vector<std::pair<std::string, std::variant<std::string>>>>> 63*86adcd6dSAndrew Geissler interfacesProperties; 64*86adcd6dSAndrew Geissler 65*86adcd6dSAndrew Geissler sdbusplus::message::object_path objPath; 66*86adcd6dSAndrew Geissler 67*86adcd6dSAndrew Geissler m.read(objPath, interfacesProperties); 68*86adcd6dSAndrew Geissler 69*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; 70*86adcd6dSAndrew Geissler for (auto &interface : interfacesProperties) 71*86adcd6dSAndrew Geissler { 72*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "interface = " << interface.first; 73*86adcd6dSAndrew Geissler 74*86adcd6dSAndrew Geissler if (interface.first == "xyz.openbmc_project.Software.Activation") 75*86adcd6dSAndrew Geissler { 76*86adcd6dSAndrew Geissler // Found our interface, disable callbacks 77*86adcd6dSAndrew Geissler fwUpdateMatcher = nullptr; 78*86adcd6dSAndrew Geissler 79*86adcd6dSAndrew Geissler // Retrieve service and activate 80*86adcd6dSAndrew Geissler crow::connections::systemBus->async_method_call( 81*86adcd6dSAndrew Geissler [objPath, asyncResp]( 82*86adcd6dSAndrew Geissler const boost::system::error_code error_code, 83*86adcd6dSAndrew Geissler const std::vector<std::pair< 84*86adcd6dSAndrew Geissler std::string, std::vector<std::string>>> &objInfo) { 85*86adcd6dSAndrew Geissler if (error_code) 86*86adcd6dSAndrew Geissler { 87*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error_code = " << error_code; 88*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "error msg = " 89*86adcd6dSAndrew Geissler << error_code.message(); 90*86adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 91*86adcd6dSAndrew Geissler cleanUp(); 92*86adcd6dSAndrew Geissler return; 93*86adcd6dSAndrew Geissler } 94*86adcd6dSAndrew Geissler // Ensure we only got one service back 95*86adcd6dSAndrew Geissler if (objInfo.size() != 1) 96*86adcd6dSAndrew Geissler { 97*86adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Invalid Object Size " 98*86adcd6dSAndrew Geissler << objInfo.size(); 99*86adcd6dSAndrew Geissler messages::internalError(asyncResp->res); 100*86adcd6dSAndrew Geissler cleanUp(); 101*86adcd6dSAndrew Geissler return; 102*86adcd6dSAndrew Geissler } 103*86adcd6dSAndrew Geissler // cancel timer only when 104*86adcd6dSAndrew Geissler // xyz.openbmc_project.Software.Activation interface 105*86adcd6dSAndrew Geissler // is added 106*86adcd6dSAndrew Geissler fwAvailableTimer = nullptr; 107*86adcd6dSAndrew Geissler 108*86adcd6dSAndrew Geissler activateImage(objPath.str, objInfo[0].first); 109*86adcd6dSAndrew Geissler redfish::messages::success(asyncResp->res); 110*86adcd6dSAndrew Geissler fwUpdateInProgress = false; 111*86adcd6dSAndrew Geissler }, 112*86adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", 113*86adcd6dSAndrew Geissler "/xyz/openbmc_project/object_mapper", 114*86adcd6dSAndrew Geissler "xyz.openbmc_project.ObjectMapper", "GetObject", objPath.str, 115*86adcd6dSAndrew Geissler std::array<const char *, 1>{ 116*86adcd6dSAndrew Geissler "xyz.openbmc_project.Software.Activation"}); 117*86adcd6dSAndrew Geissler } 118*86adcd6dSAndrew Geissler } 119*86adcd6dSAndrew Geissler } 120*86adcd6dSAndrew Geissler 121*86adcd6dSAndrew Geissler static void monitorForSoftwareAvailable(std::shared_ptr<AsyncResp> asyncResp, 122*86adcd6dSAndrew Geissler const crow::Request &req) 123*86adcd6dSAndrew Geissler { 124*86adcd6dSAndrew Geissler // Only allow one FW update at a time 125*86adcd6dSAndrew Geissler if (fwUpdateInProgress != false) 126*86adcd6dSAndrew Geissler { 127*86adcd6dSAndrew Geissler asyncResp->res.addHeader("Retry-After", "30"); 128*86adcd6dSAndrew Geissler messages::serviceTemporarilyUnavailable(asyncResp->res, "30"); 129*86adcd6dSAndrew Geissler return; 130*86adcd6dSAndrew Geissler } 131*86adcd6dSAndrew Geissler 132*86adcd6dSAndrew Geissler fwAvailableTimer = std::make_unique<boost::asio::deadline_timer>( 133*86adcd6dSAndrew Geissler *req.ioService, boost::posix_time::seconds(5)); 134*86adcd6dSAndrew Geissler 135*86adcd6dSAndrew Geissler fwAvailableTimer->expires_from_now(boost::posix_time::seconds(5)); 136*86adcd6dSAndrew Geissler 137*86adcd6dSAndrew Geissler fwAvailableTimer->async_wait( 138*86adcd6dSAndrew Geissler [asyncResp](const boost::system::error_code &ec) { 139*86adcd6dSAndrew Geissler cleanUp(); 140*86adcd6dSAndrew Geissler if (ec == boost::asio::error::operation_aborted) 141*86adcd6dSAndrew Geissler { 142*86adcd6dSAndrew Geissler // expected, we were canceled before the timer completed. 143*86adcd6dSAndrew Geissler return; 144*86adcd6dSAndrew Geissler } 145*86adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 146*86adcd6dSAndrew Geissler << "Timed out waiting for firmware object being created"; 147*86adcd6dSAndrew Geissler BMCWEB_LOG_ERROR 148*86adcd6dSAndrew Geissler << "FW image may has already been uploaded to server"; 149*86adcd6dSAndrew Geissler if (ec) 150*86adcd6dSAndrew Geissler { 151*86adcd6dSAndrew Geissler BMCWEB_LOG_ERROR << "Async_wait failed" << ec; 152*86adcd6dSAndrew Geissler return; 153*86adcd6dSAndrew Geissler } 154*86adcd6dSAndrew Geissler 155*86adcd6dSAndrew Geissler redfish::messages::internalError(asyncResp->res); 156*86adcd6dSAndrew Geissler }); 157*86adcd6dSAndrew Geissler 158*86adcd6dSAndrew Geissler auto callback = [asyncResp](sdbusplus::message::message &m) { 159*86adcd6dSAndrew Geissler BMCWEB_LOG_DEBUG << "Match fired"; 160*86adcd6dSAndrew Geissler softwareInterfaceAdded(asyncResp, m); 161*86adcd6dSAndrew Geissler }; 162*86adcd6dSAndrew Geissler 163*86adcd6dSAndrew Geissler fwUpdateInProgress = true; 164*86adcd6dSAndrew Geissler 165*86adcd6dSAndrew Geissler fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>( 166*86adcd6dSAndrew Geissler *crow::connections::systemBus, 167*86adcd6dSAndrew Geissler "interface='org.freedesktop.DBus.ObjectManager',type='signal'," 168*86adcd6dSAndrew Geissler "member='InterfacesAdded',path='/xyz/openbmc_project/software'", 169*86adcd6dSAndrew Geissler callback); 170*86adcd6dSAndrew 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 205acb7cfb4SJennifer Lee void doPost(crow::Response &res, const crow::Request &req, 2061abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2071abe55efSEd Tanous { 208acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "doPost..."; 209acb7cfb4SJennifer Lee 2100e7de46fSAndrew Geissler std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 211acb7cfb4SJennifer Lee 212*86adcd6dSAndrew Geissler // Setup callback for when new software detected 213*86adcd6dSAndrew Geissler monitorForSoftwareAvailable(asyncResp, req); 214acb7cfb4SJennifer Lee 215acb7cfb4SJennifer Lee std::string filepath( 216acb7cfb4SJennifer Lee "/tmp/images/" + 217acb7cfb4SJennifer Lee boost::uuids::to_string(boost::uuids::random_generator()())); 218acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "Writing file to " << filepath; 219acb7cfb4SJennifer Lee std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary | 220acb7cfb4SJennifer Lee std::ofstream::trunc); 221acb7cfb4SJennifer Lee out << req.body; 222acb7cfb4SJennifer Lee out.close(); 223acb7cfb4SJennifer Lee BMCWEB_LOG_DEBUG << "file upload complete!!"; 224acb7cfb4SJennifer Lee } 225729dae72SJennifer Lee }; 226729dae72SJennifer Lee 2271abe55efSEd Tanous class SoftwareInventoryCollection : public Node 2281abe55efSEd Tanous { 229729dae72SJennifer Lee public: 230729dae72SJennifer Lee template <typename CrowApp> 2311abe55efSEd Tanous SoftwareInventoryCollection(CrowApp &app) : 2321abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") 2331abe55efSEd Tanous { 234729dae72SJennifer Lee entityPrivileges = { 235729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 236729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 237729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 238729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 239729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 240729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 241729dae72SJennifer Lee } 242729dae72SJennifer Lee 243729dae72SJennifer Lee private: 24455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 2451abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2461abe55efSEd Tanous { 247c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 2480f74e643SEd Tanous res.jsonValue["@odata.type"] = 2490f74e643SEd Tanous "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 2500f74e643SEd Tanous res.jsonValue["@odata.id"] = 2510f74e643SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory"; 2520f74e643SEd Tanous res.jsonValue["@odata.context"] = 2530f74e643SEd Tanous "/redfish/v1/" 2540f74e643SEd Tanous "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 2550f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory Collection"; 256c711bf86SEd Tanous 257c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 258c711bf86SEd Tanous [asyncResp]( 259c711bf86SEd Tanous const boost::system::error_code ec, 2606c4eb9deSJennifer Lee const std::vector<std::pair< 2611abe55efSEd Tanous std::string, std::vector<std::pair< 2621abe55efSEd Tanous std::string, std::vector<std::string>>>>> 2636c4eb9deSJennifer Lee &subtree) { 2641abe55efSEd Tanous if (ec) 2651abe55efSEd Tanous { 266f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2676c4eb9deSJennifer Lee return; 268729dae72SJennifer Lee } 269c711bf86SEd Tanous asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 270c711bf86SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 0; 2716c4eb9deSJennifer Lee 2721abe55efSEd Tanous for (auto &obj : subtree) 2731abe55efSEd Tanous { 2741abe55efSEd Tanous const std::vector< 2751abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 2766c4eb9deSJennifer Lee &connections = obj.second; 2776c4eb9deSJennifer Lee 278f4b65ab1SJennifer Lee // if can't parse fw id then return 27927826b5fSEd Tanous std::size_t idPos; 28027826b5fSEd Tanous if ((idPos = obj.first.rfind("/")) == std::string::npos) 281f4b65ab1SJennifer Lee { 282f12894f8SJason M. Bills messages::internalError(asyncResp->res); 283f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Can't parse firmware ID!!"; 284f4b65ab1SJennifer Lee return; 285f4b65ab1SJennifer Lee } 286f4b65ab1SJennifer Lee std::string swId = obj.first.substr(idPos + 1); 287f4b65ab1SJennifer Lee 2881abe55efSEd Tanous for (auto &conn : connections) 2891abe55efSEd Tanous { 290c711bf86SEd Tanous const std::string &connectionName = conn.first; 2911abe55efSEd Tanous BMCWEB_LOG_DEBUG << "connectionName = " 2921abe55efSEd Tanous << connectionName; 29355c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "obj.first = " << obj.first; 2946c4eb9deSJennifer Lee 29555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 296f4b65ab1SJennifer Lee [asyncResp, 297f4b65ab1SJennifer Lee swId](const boost::system::error_code error_code, 298c711bf86SEd Tanous const VariantType &activation) { 2991abe55efSEd Tanous BMCWEB_LOG_DEBUG 3001abe55efSEd Tanous << "safe returned in lambda function"; 3011abe55efSEd Tanous if (error_code) 3021abe55efSEd Tanous { 303f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3046c4eb9deSJennifer Lee return; 3056c4eb9deSJennifer Lee } 306c711bf86SEd Tanous 307f4b65ab1SJennifer Lee const std::string *swActivationStatus = 308abf2add6SEd Tanous std::get_if<std::string>(&activation); 309f4b65ab1SJennifer Lee if (swActivationStatus == nullptr) 3101abe55efSEd Tanous { 311f12894f8SJason M. Bills messages::internalError(asyncResp->res); 312acb7cfb4SJennifer Lee return; 313acb7cfb4SJennifer Lee } 314f4b65ab1SJennifer Lee if (swActivationStatus != nullptr && 315f4b65ab1SJennifer Lee *swActivationStatus != 316f4b65ab1SJennifer Lee "xyz.openbmc_project.Software." 317f4b65ab1SJennifer Lee "Activation." 318f4b65ab1SJennifer Lee "Activations.Active") 3191abe55efSEd Tanous { 320f4b65ab1SJennifer Lee // The activation status of this software is 321f4b65ab1SJennifer Lee // not currently active, so does not need to 322f4b65ab1SJennifer Lee // be listed in the response 323c711bf86SEd Tanous return; 324c711bf86SEd Tanous } 325c711bf86SEd Tanous nlohmann::json &members = 326c711bf86SEd Tanous asyncResp->res.jsonValue["Members"]; 327c711bf86SEd Tanous members.push_back( 328f4b65ab1SJennifer Lee {{"@odata.id", "/redfish/v1/UpdateService/" 3291abe55efSEd Tanous "FirmwareInventory/" + 330f4b65ab1SJennifer Lee swId}}); 3311abe55efSEd Tanous asyncResp->res 3321abe55efSEd Tanous .jsonValue["Members@odata.count"] = 333c711bf86SEd Tanous members.size(); 3346c4eb9deSJennifer Lee }, 3351abe55efSEd Tanous connectionName, obj.first, 3361abe55efSEd Tanous "org.freedesktop.DBus.Properties", "Get", 3371abe55efSEd Tanous "xyz.openbmc_project.Software.Activation", 338acb7cfb4SJennifer Lee "Activation"); 3396c4eb9deSJennifer Lee } 3406c4eb9deSJennifer Lee } 341c711bf86SEd Tanous }, 342c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 343c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 344c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 345c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 3461abe55efSEd Tanous std::array<const char *, 1>{ 3471abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 348729dae72SJennifer Lee } 349729dae72SJennifer Lee }; 350c711bf86SEd Tanous 3511abe55efSEd Tanous class SoftwareInventory : public Node 3521abe55efSEd Tanous { 353729dae72SJennifer Lee public: 354729dae72SJennifer Lee template <typename CrowApp> 3551abe55efSEd Tanous SoftwareInventory(CrowApp &app) : 3561abe55efSEd Tanous Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/", 3571abe55efSEd Tanous std::string()) 3581abe55efSEd Tanous { 359729dae72SJennifer Lee entityPrivileges = { 360729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 361729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 362729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 363729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 364729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 365729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 366729dae72SJennifer Lee } 367729dae72SJennifer Lee 368729dae72SJennifer Lee private: 36987d84729SAndrew Geissler /* Fill related item links (i.e. bmc, bios) in for inventory */ 37087d84729SAndrew Geissler static void getRelatedItems(std::shared_ptr<AsyncResp> aResp, 37187d84729SAndrew Geissler const std::string &purpose) 37287d84729SAndrew Geissler { 37387d84729SAndrew Geissler if (purpose == fw_util::bmcPurpose) 37487d84729SAndrew Geissler { 37587d84729SAndrew Geissler nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 37687d84729SAndrew Geissler members.push_back({{"@odata.id", "/redfish/v1/Managers/bmc"}}); 37787d84729SAndrew Geissler aResp->res.jsonValue["Members@odata.count"] = members.size(); 37887d84729SAndrew Geissler } 37987d84729SAndrew Geissler else if (purpose == fw_util::biosPurpose) 38087d84729SAndrew Geissler { 38187d84729SAndrew Geissler // TODO(geissonator) Need BIOS schema support added for this 38287d84729SAndrew Geissler // to be valid 38387d84729SAndrew Geissler // nlohmann::json &members = aResp->res.jsonValue["RelatedItem"]; 38487d84729SAndrew Geissler // members.push_back( 38587d84729SAndrew Geissler // {{"@odata.id", "/redfish/v1/Systems/system/BIOS"}}); 38687d84729SAndrew Geissler // aResp->res.jsonValue["Members@odata.count"] = members.size(); 38787d84729SAndrew Geissler } 38887d84729SAndrew Geissler else 38987d84729SAndrew Geissler { 39087d84729SAndrew Geissler BMCWEB_LOG_ERROR << "Unknown software purpose " << purpose; 39187d84729SAndrew Geissler } 39287d84729SAndrew Geissler } 39387d84729SAndrew Geissler 39455c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 3951abe55efSEd Tanous const std::vector<std::string> ¶ms) override 3961abe55efSEd Tanous { 397c711bf86SEd Tanous std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 3980f74e643SEd Tanous res.jsonValue["@odata.type"] = 3990f74e643SEd Tanous "#SoftwareInventory.v1_1_0.SoftwareInventory"; 4000f74e643SEd Tanous res.jsonValue["@odata.context"] = 4010f74e643SEd Tanous "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 4020f74e643SEd Tanous res.jsonValue["Name"] = "Software Inventory"; 4030f74e643SEd Tanous res.jsonValue["Updateable"] = false; 4040f74e643SEd Tanous res.jsonValue["Status"]["Health"] = "OK"; 4050f74e643SEd Tanous res.jsonValue["Status"]["HealthRollup"] = "OK"; 4060f74e643SEd Tanous res.jsonValue["Status"]["State"] = "Enabled"; 4076c4eb9deSJennifer Lee 4081abe55efSEd Tanous if (params.size() != 1) 4091abe55efSEd Tanous { 410f12894f8SJason M. Bills messages::internalError(res); 411729dae72SJennifer Lee res.end(); 412729dae72SJennifer Lee return; 413729dae72SJennifer Lee } 414729dae72SJennifer Lee 4153ae837c9SEd Tanous std::shared_ptr<std::string> swId = 416c711bf86SEd Tanous std::make_shared<std::string>(params[0]); 417c711bf86SEd Tanous 41855c7b7a2SEd Tanous res.jsonValue["@odata.id"] = 4193ae837c9SEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/" + *swId; 420c711bf86SEd Tanous 421c711bf86SEd Tanous crow::connections::systemBus->async_method_call( 4223ae837c9SEd Tanous [asyncResp, swId]( 423c711bf86SEd Tanous const boost::system::error_code ec, 4246c4eb9deSJennifer Lee const std::vector<std::pair< 4251abe55efSEd Tanous std::string, std::vector<std::pair< 4261abe55efSEd Tanous std::string, std::vector<std::string>>>>> 4276c4eb9deSJennifer Lee &subtree) { 42855c7b7a2SEd Tanous BMCWEB_LOG_DEBUG << "doGet callback..."; 4291abe55efSEd Tanous if (ec) 4301abe55efSEd Tanous { 431f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4326c4eb9deSJennifer Lee return; 4336c4eb9deSJennifer Lee } 4346c4eb9deSJennifer Lee 4351abe55efSEd Tanous for (const std::pair< 4361abe55efSEd Tanous std::string, 4371abe55efSEd Tanous std::vector< 4381abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 4391abe55efSEd Tanous &obj : subtree) 4401abe55efSEd Tanous { 4413ae837c9SEd Tanous if (boost::ends_with(obj.first, *swId) != true) 4421abe55efSEd Tanous { 443acb7cfb4SJennifer Lee continue; 444acb7cfb4SJennifer Lee } 445acb7cfb4SJennifer Lee 446f4b65ab1SJennifer Lee if (obj.second.size() < 1) 4471abe55efSEd Tanous { 448acb7cfb4SJennifer Lee continue; 449acb7cfb4SJennifer Lee } 4506c4eb9deSJennifer Lee 45155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 4521abe55efSEd Tanous [asyncResp, 4533ae837c9SEd Tanous swId](const boost::system::error_code error_code, 4541abe55efSEd Tanous const boost::container::flat_map< 4551abe55efSEd Tanous std::string, VariantType> &propertiesList) { 4561abe55efSEd Tanous if (error_code) 4571abe55efSEd Tanous { 458f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4596c4eb9deSJennifer Lee return; 4606c4eb9deSJennifer Lee } 4611abe55efSEd Tanous boost::container::flat_map< 4621abe55efSEd Tanous std::string, VariantType>::const_iterator it = 4636c4eb9deSJennifer Lee propertiesList.find("Purpose"); 4641abe55efSEd Tanous if (it == propertiesList.end()) 4651abe55efSEd Tanous { 4661abe55efSEd Tanous BMCWEB_LOG_DEBUG 4671abe55efSEd Tanous << "Can't find property \"Purpose\"!"; 468f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 469f12894f8SJason M. Bills "Purpose"); 4706c4eb9deSJennifer Lee return; 4716c4eb9deSJennifer Lee } 4723ae837c9SEd Tanous const std::string *swInvPurpose = 473abf2add6SEd Tanous std::get_if<std::string>(&it->second); 4743ae837c9SEd Tanous if (swInvPurpose == nullptr) 4751abe55efSEd Tanous { 4761abe55efSEd Tanous BMCWEB_LOG_DEBUG 4771abe55efSEd Tanous << "wrong types for property\"Purpose\"!"; 478f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 479f12894f8SJason M. Bills "", "Purpose"); 480acb7cfb4SJennifer Lee return; 481acb7cfb4SJennifer Lee } 482c711bf86SEd Tanous 4833ae837c9SEd Tanous BMCWEB_LOG_DEBUG << "swInvPurpose = " 4843ae837c9SEd Tanous << *swInvPurpose; 485c711bf86SEd Tanous it = propertiesList.find("Version"); 4861abe55efSEd Tanous if (it == propertiesList.end()) 4871abe55efSEd Tanous { 4881abe55efSEd Tanous BMCWEB_LOG_DEBUG 4891abe55efSEd Tanous << "Can't find property \"Version\"!"; 490f12894f8SJason M. Bills messages::propertyMissing(asyncResp->res, 491f12894f8SJason M. Bills "Version"); 492c711bf86SEd Tanous return; 493acb7cfb4SJennifer Lee } 494acb7cfb4SJennifer Lee 495f4b65ab1SJennifer Lee BMCWEB_LOG_DEBUG << "Version found!"; 496c711bf86SEd Tanous 497f4b65ab1SJennifer Lee const std::string *version = 498abf2add6SEd Tanous std::get_if<std::string>(&it->second); 499f4b65ab1SJennifer Lee 500f4b65ab1SJennifer Lee if (version == nullptr) 5011abe55efSEd Tanous { 5021abe55efSEd Tanous BMCWEB_LOG_DEBUG 5031abe55efSEd Tanous << "Can't find property \"Version\"!"; 504f12894f8SJason M. Bills 505f12894f8SJason M. Bills messages::propertyValueTypeError(asyncResp->res, 506f12894f8SJason M. Bills "", "Version"); 5076c4eb9deSJennifer Lee return; 5086c4eb9deSJennifer Lee } 509c711bf86SEd Tanous asyncResp->res.jsonValue["Version"] = *version; 5103ae837c9SEd Tanous asyncResp->res.jsonValue["Id"] = *swId; 51154daabe7SAndrew Geissler 51254daabe7SAndrew Geissler // swInvPurpose is of format: 51354daabe7SAndrew Geissler // xyz.openbmc_project.Software.Version.VersionPurpose.ABC 51454daabe7SAndrew Geissler // Translate this to "ABC update" 51554daabe7SAndrew Geissler size_t endDesc = swInvPurpose->rfind("."); 51654daabe7SAndrew Geissler if (endDesc == std::string::npos) 51754daabe7SAndrew Geissler { 51854daabe7SAndrew Geissler messages::internalError(asyncResp->res); 51954daabe7SAndrew Geissler return; 52054daabe7SAndrew Geissler } 52154daabe7SAndrew Geissler endDesc++; 52254daabe7SAndrew Geissler if (endDesc >= swInvPurpose->size()) 52354daabe7SAndrew Geissler { 52454daabe7SAndrew Geissler messages::internalError(asyncResp->res); 52554daabe7SAndrew Geissler return; 52654daabe7SAndrew Geissler } 52754daabe7SAndrew Geissler 52854daabe7SAndrew Geissler std::string formatDesc = 52954daabe7SAndrew Geissler swInvPurpose->substr(endDesc); 53054daabe7SAndrew Geissler asyncResp->res.jsonValue["Description"] = 53154daabe7SAndrew Geissler formatDesc + " update"; 53287d84729SAndrew Geissler getRelatedItems(asyncResp, *swInvPurpose); 5336c4eb9deSJennifer Lee }, 534c711bf86SEd Tanous obj.second[0].first, obj.first, 535c711bf86SEd Tanous "org.freedesktop.DBus.Properties", "GetAll", 536c711bf86SEd Tanous "xyz.openbmc_project.Software.Version"); 5376c4eb9deSJennifer Lee } 538c711bf86SEd Tanous }, 539c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", 540c711bf86SEd Tanous "/xyz/openbmc_project/object_mapper", 541c711bf86SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 542c711bf86SEd Tanous "/xyz/openbmc_project/software", int32_t(1), 5431abe55efSEd Tanous std::array<const char *, 1>{ 5441abe55efSEd Tanous "xyz.openbmc_project.Software.Version"}); 5456c4eb9deSJennifer Lee } 546729dae72SJennifer Lee }; 547729dae72SJennifer Lee 548729dae72SJennifer Lee } // namespace redfish 549