1*729dae72SJennifer Lee /* 2*729dae72SJennifer Lee // Copyright (c) 2018 Intel Corporation 3*729dae72SJennifer Lee // 4*729dae72SJennifer Lee // Licensed under the Apache License, Version 2.0 (the "License"); 5*729dae72SJennifer Lee // you may not use this file except in compliance with the License. 6*729dae72SJennifer Lee // You may obtain a copy of the License at 7*729dae72SJennifer Lee // 8*729dae72SJennifer Lee // http://www.apache.org/licenses/LICENSE-2.0 9*729dae72SJennifer Lee // 10*729dae72SJennifer Lee // Unless required by applicable law or agreed to in writing, software 11*729dae72SJennifer Lee // distributed under the License is distributed on an "AS IS" BASIS, 12*729dae72SJennifer Lee // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*729dae72SJennifer Lee // See the License for the specific language governing permissions and 14*729dae72SJennifer Lee // limitations under the License. 15*729dae72SJennifer Lee */ 16*729dae72SJennifer Lee #pragma once 17*729dae72SJennifer Lee 18*729dae72SJennifer Lee #include "node.hpp" 19*729dae72SJennifer Lee #include <boost/container/flat_map.hpp> 20*729dae72SJennifer Lee 21*729dae72SJennifer Lee namespace redfish { 22*729dae72SJennifer Lee 23*729dae72SJennifer Lee class OnDemandSoftwareInventoryProvider { 24*729dae72SJennifer Lee public: 25*729dae72SJennifer Lee template <typename CallbackFunc> 26*729dae72SJennifer Lee void get_all_software_inventory_data(CallbackFunc &&callback) { 27*729dae72SJennifer Lee crow::connections::system_bus->async_method_call( 28*729dae72SJennifer Lee [callback{std::move(callback)}]( 29*729dae72SJennifer Lee const boost::system::error_code error_code, 30*729dae72SJennifer Lee const std::vector<std::pair< 31*729dae72SJennifer Lee std::string, 32*729dae72SJennifer Lee std::vector<std::pair<std::string, std::vector<std::string>>>>> 33*729dae72SJennifer Lee &subtree) { 34*729dae72SJennifer Lee 35*729dae72SJennifer Lee std::vector<boost::container::flat_map<std::string, std::string>> 36*729dae72SJennifer Lee output; 37*729dae72SJennifer Lee 38*729dae72SJennifer Lee if (error_code) { 39*729dae72SJennifer Lee // Something wrong on DBus, the error_code is not important at this 40*729dae72SJennifer Lee // moment, just return success=false, and empty output. Since size 41*729dae72SJennifer Lee // of vector may vary depending on information from Entity Manager, 42*729dae72SJennifer Lee // and empty output could not be treated same way as error. 43*729dae72SJennifer Lee callback(false, output); 44*729dae72SJennifer Lee return; 45*729dae72SJennifer Lee } 46*729dae72SJennifer Lee 47*729dae72SJennifer Lee for (auto &obj : subtree) { 48*729dae72SJennifer Lee const std::vector<std::pair<std::string, std::vector<std::string>>> 49*729dae72SJennifer Lee &connectionNames = obj.second; 50*729dae72SJennifer Lee 51*729dae72SJennifer Lee const std::string connectionName = connectionNames[0].first; 52*729dae72SJennifer Lee 53*729dae72SJennifer Lee crow::connections::system_bus->async_method_call( 54*729dae72SJennifer Lee [&](const boost::system::error_code error_code, 55*729dae72SJennifer Lee const std::vector<std::pair<std::string, VariantType>> 56*729dae72SJennifer Lee &propertiesList) { 57*729dae72SJennifer Lee for (auto &property : propertiesList) { 58*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string> 59*729dae72SJennifer Lee single_sw_item_properties; 60*729dae72SJennifer Lee single_sw_item_properties[property.first] = 61*729dae72SJennifer Lee *(mapbox::get_ptr<const std::string>(property.second)); 62*729dae72SJennifer Lee output.emplace_back(single_sw_item_properties); 63*729dae72SJennifer Lee } 64*729dae72SJennifer Lee }, 65*729dae72SJennifer Lee connectionName, obj.first, "org.freedesktop.DBus.Properties", 66*729dae72SJennifer Lee "GetAll", "xyz.openbmc_project.Software.Version"); 67*729dae72SJennifer Lee // Finally make a callback with usefull data 68*729dae72SJennifer Lee callback(true, output); 69*729dae72SJennifer Lee } 70*729dae72SJennifer Lee }, 71*729dae72SJennifer Lee "xyz.openbmc_project.ObjectMapper", 72*729dae72SJennifer Lee "/xyz/openbmc_project/object_mapper", 73*729dae72SJennifer Lee "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 74*729dae72SJennifer Lee "/xyz/openbmc_project/software", int32_t(0), 75*729dae72SJennifer Lee std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"}); 76*729dae72SJennifer Lee } 77*729dae72SJennifer Lee /* 78*729dae72SJennifer Lee * Function that retrieves all SoftwareInventory available through 79*729dae72SJennifer Lee * Software.BMC.Updater. 80*729dae72SJennifer Lee * @param callback a function that shall be called to convert Dbus output into 81*729dae72SJennifer Lee * JSON. 82*729dae72SJennifer Lee */ 83*729dae72SJennifer Lee template <typename CallbackFunc> 84*729dae72SJennifer Lee void get_software_inventory_list(CallbackFunc &&callback) { 85*729dae72SJennifer Lee get_all_software_inventory_data( 86*729dae72SJennifer Lee [callback]( 87*729dae72SJennifer Lee const bool &success, 88*729dae72SJennifer Lee const std::vector< 89*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string>> &output) { 90*729dae72SJennifer Lee std::vector<std::string> sw_inv_list; 91*729dae72SJennifer Lee for (auto &i : output) { 92*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string>::const_iterator 93*729dae72SJennifer Lee p = i.find("Purpose"); 94*729dae72SJennifer Lee if ((p != i.end())) { 95*729dae72SJennifer Lee const std::string &sw_inv_purpose = 96*729dae72SJennifer Lee boost::get<std::string>(p->second); 97*729dae72SJennifer Lee std::size_t last_pos = sw_inv_purpose.rfind("."); 98*729dae72SJennifer Lee if (last_pos != std::string::npos) { 99*729dae72SJennifer Lee // and put it into output vector. 100*729dae72SJennifer Lee sw_inv_list.emplace_back(sw_inv_purpose.substr(last_pos + 1)); 101*729dae72SJennifer Lee } 102*729dae72SJennifer Lee } 103*729dae72SJennifer Lee } 104*729dae72SJennifer Lee callback(true, sw_inv_list); 105*729dae72SJennifer Lee }); 106*729dae72SJennifer Lee }; 107*729dae72SJennifer Lee 108*729dae72SJennifer Lee template <typename CallbackFunc> 109*729dae72SJennifer Lee void get_software_inventory_data(const std::string &res_name, 110*729dae72SJennifer Lee CallbackFunc &&callback) { 111*729dae72SJennifer Lee get_all_software_inventory_data( 112*729dae72SJennifer Lee [res_name, callback]( 113*729dae72SJennifer Lee const bool &success, 114*729dae72SJennifer Lee const std::vector< 115*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string>> &output) { 116*729dae72SJennifer Lee for (auto &i : output) { 117*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string>::const_iterator 118*729dae72SJennifer Lee p = i.find("Purpose"); 119*729dae72SJennifer Lee // Find the one with Purpose matching res_name 120*729dae72SJennifer Lee if ((p != i.end()) && 121*729dae72SJennifer Lee boost::ends_with(boost::get<std::string>(p->second), 122*729dae72SJennifer Lee "." + res_name)) { 123*729dae72SJennifer Lee callback(true, i); 124*729dae72SJennifer Lee } 125*729dae72SJennifer Lee } 126*729dae72SJennifer Lee }); 127*729dae72SJennifer Lee } 128*729dae72SJennifer Lee }; 129*729dae72SJennifer Lee 130*729dae72SJennifer Lee class UpdateService : public Node { 131*729dae72SJennifer Lee public: 132*729dae72SJennifer Lee UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") { 133*729dae72SJennifer Lee Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; 134*729dae72SJennifer Lee Node::json["@odata.id"] = "/redfish/v1/UpdateService"; 135*729dae72SJennifer Lee Node::json["@odata.context"] = 136*729dae72SJennifer Lee "/redfish/v1/$metadata#UpdateService.UpdateService"; 137*729dae72SJennifer Lee Node::json["Id"] = "UpdateService"; 138*729dae72SJennifer Lee Node::json["Description"] = "Service for Software Update"; 139*729dae72SJennifer Lee Node::json["Name"] = "Update Service"; 140*729dae72SJennifer Lee Node::json["ServiceEnabled"] = true; // UpdateService cannot be disabled 141*729dae72SJennifer Lee Node::json["SoftwareInventory"] = { 142*729dae72SJennifer Lee {"@odata.id", "/redfish/v1/UpdateService/SoftwareInventory"}}; 143*729dae72SJennifer Lee 144*729dae72SJennifer Lee entityPrivileges = { 145*729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 146*729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 147*729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 148*729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 149*729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 150*729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 151*729dae72SJennifer Lee } 152*729dae72SJennifer Lee 153*729dae72SJennifer Lee private: 154*729dae72SJennifer Lee void doGet(crow::response &res, const crow::request &req, 155*729dae72SJennifer Lee const std::vector<std::string> ¶ms) override { 156*729dae72SJennifer Lee res.json_value = Node::json; 157*729dae72SJennifer Lee res.end(); 158*729dae72SJennifer Lee } 159*729dae72SJennifer Lee }; 160*729dae72SJennifer Lee 161*729dae72SJennifer Lee class SoftwareInventoryCollection : public Node { 162*729dae72SJennifer Lee public: 163*729dae72SJennifer Lee /* 164*729dae72SJennifer Lee * Default Constructor 165*729dae72SJennifer Lee */ 166*729dae72SJennifer Lee template <typename CrowApp> 167*729dae72SJennifer Lee SoftwareInventoryCollection(CrowApp &app) 168*729dae72SJennifer Lee : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/") { 169*729dae72SJennifer Lee Node::json["@odata.type"] = 170*729dae72SJennifer Lee "#SoftwareInventoryCollection.SoftwareInventoryCollection"; 171*729dae72SJennifer Lee Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; 172*729dae72SJennifer Lee Node::json["@odata.context"] = 173*729dae72SJennifer Lee "/redfish/v1/" 174*729dae72SJennifer Lee "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; 175*729dae72SJennifer Lee Node::json["Name"] = "Software Inventory Collection"; 176*729dae72SJennifer Lee 177*729dae72SJennifer Lee entityPrivileges = { 178*729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 179*729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 180*729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 181*729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 182*729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 183*729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 184*729dae72SJennifer Lee } 185*729dae72SJennifer Lee 186*729dae72SJennifer Lee private: 187*729dae72SJennifer Lee /** 188*729dae72SJennifer Lee * Functions triggers appropriate requests on DBus 189*729dae72SJennifer Lee */ 190*729dae72SJennifer Lee void doGet(crow::response &res, const crow::request &req, 191*729dae72SJennifer Lee const std::vector<std::string> ¶ms) override { 192*729dae72SJennifer Lee res.json_value = Node::json; 193*729dae72SJennifer Lee // Get sw inventory list, and call the below callback for JSON preparation 194*729dae72SJennifer Lee software_inventory_provider.get_software_inventory_list( 195*729dae72SJennifer Lee [&](const bool &success, const std::vector<std::string> &output) { 196*729dae72SJennifer Lee 197*729dae72SJennifer Lee if (success) { 198*729dae72SJennifer Lee // ... prepare json array with appropriate @odata.id links 199*729dae72SJennifer Lee nlohmann::json sw_inventory_array = nlohmann::json::array(); 200*729dae72SJennifer Lee for (const std::string &sw_item : output) { 201*729dae72SJennifer Lee sw_inventory_array.push_back( 202*729dae72SJennifer Lee {{"@odata.id", 203*729dae72SJennifer Lee "/redfish/v1/UpdateService/SoftwareInventory/" + sw_item}}); 204*729dae72SJennifer Lee } 205*729dae72SJennifer Lee // Then attach members, count size and return 206*729dae72SJennifer Lee 207*729dae72SJennifer Lee Node::json["Members"] = sw_inventory_array; 208*729dae72SJennifer Lee Node::json["Members@odata.count"] = sw_inventory_array.size(); 209*729dae72SJennifer Lee res.json_value = Node::json; 210*729dae72SJennifer Lee } else { 211*729dae72SJennifer Lee // ... otherwise, return INTERNALL ERROR 212*729dae72SJennifer Lee res.result(boost::beast::http::status::internal_server_error); 213*729dae72SJennifer Lee } 214*729dae72SJennifer Lee res.end(); 215*729dae72SJennifer Lee }); 216*729dae72SJennifer Lee res.end(); 217*729dae72SJennifer Lee } 218*729dae72SJennifer Lee OnDemandSoftwareInventoryProvider software_inventory_provider; 219*729dae72SJennifer Lee }; 220*729dae72SJennifer Lee /** 221*729dae72SJennifer Lee * Chassis override class for delivering Chassis Schema 222*729dae72SJennifer Lee */ 223*729dae72SJennifer Lee class SoftwareInventory : public Node { 224*729dae72SJennifer Lee public: 225*729dae72SJennifer Lee /* 226*729dae72SJennifer Lee * Default Constructor 227*729dae72SJennifer Lee */ 228*729dae72SJennifer Lee template <typename CrowApp> 229*729dae72SJennifer Lee SoftwareInventory(CrowApp &app) 230*729dae72SJennifer Lee : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/<str>/", 231*729dae72SJennifer Lee std::string()) { 232*729dae72SJennifer Lee Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory"; 233*729dae72SJennifer Lee Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; 234*729dae72SJennifer Lee Node::json["@odata.context"] = 235*729dae72SJennifer Lee "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; 236*729dae72SJennifer Lee Node::json["Name"] = "Software Inventory"; 237*729dae72SJennifer Lee Node::json["Status"] = "OK"; // TODO 238*729dae72SJennifer Lee Node::json["Updateable"] = "No"; 239*729dae72SJennifer Lee 240*729dae72SJennifer Lee entityPrivileges = { 241*729dae72SJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 242*729dae72SJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 243*729dae72SJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 244*729dae72SJennifer Lee {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 245*729dae72SJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 246*729dae72SJennifer Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 247*729dae72SJennifer Lee } 248*729dae72SJennifer Lee 249*729dae72SJennifer Lee private: 250*729dae72SJennifer Lee /** 251*729dae72SJennifer Lee * Functions triggers appropriate requests on DBus 252*729dae72SJennifer Lee */ 253*729dae72SJennifer Lee void doGet(crow::response &res, const crow::request &req, 254*729dae72SJennifer Lee const std::vector<std::string> ¶ms) override { 255*729dae72SJennifer Lee if (params.size() != 1) { 256*729dae72SJennifer Lee res.result(boost::beast::http::status::internal_server_error); 257*729dae72SJennifer Lee res.end(); 258*729dae72SJennifer Lee return; 259*729dae72SJennifer Lee } 260*729dae72SJennifer Lee const std::string &sw_id = params[0]; 261*729dae72SJennifer Lee software_inventory_provider.get_software_inventory_data( 262*729dae72SJennifer Lee sw_id, [&, id{std::string(sw_id)} ]( 263*729dae72SJennifer Lee const bool &success, 264*729dae72SJennifer Lee const boost::container::flat_map<std::string, std::string> 265*729dae72SJennifer Lee &output) { 266*729dae72SJennifer Lee res.json_value = Node::json; 267*729dae72SJennifer Lee // If success... 268*729dae72SJennifer Lee if (success) { 269*729dae72SJennifer Lee // prepare all the schema required fields. 270*729dae72SJennifer Lee res.json_value["@odata.id"] = 271*729dae72SJennifer Lee "/redfish/v1/UpdateService/SoftwareInventory/" + id; 272*729dae72SJennifer Lee // also the one from dbus 273*729dae72SJennifer Lee boost::container::flat_map<std::string, std::string>::const_iterator 274*729dae72SJennifer Lee it = output.find("Version"); 275*729dae72SJennifer Lee res.json_value["Version"] = boost::get<std::string>(it->second); 276*729dae72SJennifer Lee 277*729dae72SJennifer Lee res.json_value["Id"] = id; 278*729dae72SJennifer Lee // prepare respond, and send 279*729dae72SJennifer Lee } else { 280*729dae72SJennifer Lee res.result(boost::beast::http::status::not_found); 281*729dae72SJennifer Lee } 282*729dae72SJennifer Lee res.end(); 283*729dae72SJennifer Lee }); 284*729dae72SJennifer Lee } 285*729dae72SJennifer Lee 286*729dae72SJennifer Lee OnDemandSoftwareInventoryProvider software_inventory_provider; 287*729dae72SJennifer Lee }; 288*729dae72SJennifer Lee 289*729dae72SJennifer Lee } // namespace redfish 290