/* // Copyright (c) 2018 Intel Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. */ #pragma once #include "node.hpp" #include namespace redfish { class OnDemandSoftwareInventoryProvider { public: template void get_all_software_inventory_data(CallbackFunc &&callback) { crow::connections::system_bus->async_method_call( [callback{std::move(callback)}]( const boost::system::error_code error_code, const std::vector>>>> &subtree) { std::vector> output; if (error_code) { // Something wrong on DBus, the error_code is not important at this // moment, just return success=false, and empty output. Since size // of vector may vary depending on information from Entity Manager, // and empty output could not be treated same way as error. callback(false, output); return; } for (auto &obj : subtree) { const std::vector>> &connectionNames = obj.second; const std::string connectionName = connectionNames[0].first; crow::connections::system_bus->async_method_call( [&](const boost::system::error_code error_code, const std::vector> &propertiesList) { for (auto &property : propertiesList) { boost::container::flat_map single_sw_item_properties; single_sw_item_properties[property.first] = *(mapbox::get_ptr(property.second)); output.emplace_back(single_sw_item_properties); } }, connectionName, obj.first, "org.freedesktop.DBus.Properties", "GetAll", "xyz.openbmc_project.Software.Version"); // Finally make a callback with usefull data callback(true, output); } }, "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/xyz/openbmc_project/software", int32_t(0), std::array{"xyz.openbmc_project.Software.Version"}); } /* * Function that retrieves all SoftwareInventory available through * Software.BMC.Updater. * @param callback a function that shall be called to convert Dbus output into * JSON. */ template void get_software_inventory_list(CallbackFunc &&callback) { get_all_software_inventory_data( [callback]( const bool &success, const std::vector< boost::container::flat_map> &output) { std::vector sw_inv_list; for (auto &i : output) { boost::container::flat_map::const_iterator p = i.find("Purpose"); if ((p != i.end())) { const std::string &sw_inv_purpose = boost::get(p->second); std::size_t last_pos = sw_inv_purpose.rfind("."); if (last_pos != std::string::npos) { // and put it into output vector. sw_inv_list.emplace_back(sw_inv_purpose.substr(last_pos + 1)); } } } callback(true, sw_inv_list); }); }; template void get_software_inventory_data(const std::string &res_name, CallbackFunc &&callback) { get_all_software_inventory_data( [res_name, callback]( const bool &success, const std::vector< boost::container::flat_map> &output) { for (auto &i : output) { boost::container::flat_map::const_iterator p = i.find("Purpose"); // Find the one with Purpose matching res_name if ((p != i.end()) && boost::ends_with(boost::get(p->second), "." + res_name)) { callback(true, i); } } }); } }; class UpdateService : public Node { public: UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") { Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService"; Node::json["@odata.id"] = "/redfish/v1/UpdateService"; Node::json["@odata.context"] = "/redfish/v1/$metadata#UpdateService.UpdateService"; Node::json["Id"] = "UpdateService"; Node::json["Description"] = "Service for Software Update"; Node::json["Name"] = "Update Service"; Node::json["ServiceEnabled"] = true; // UpdateService cannot be disabled Node::json["SoftwareInventory"] = { {"@odata.id", "/redfish/v1/UpdateService/SoftwareInventory"}}; entityPrivileges = { {boost::beast::http::verb::get, {{"Login"}}}, {boost::beast::http::verb::head, {{"Login"}}}, {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; } private: void doGet(crow::response &res, const crow::request &req, const std::vector ¶ms) override { res.json_value = Node::json; res.end(); } }; class SoftwareInventoryCollection : public Node { public: /* * Default Constructor */ template SoftwareInventoryCollection(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/") { Node::json["@odata.type"] = "#SoftwareInventoryCollection.SoftwareInventoryCollection"; Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; Node::json["@odata.context"] = "/redfish/v1/" "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection"; Node::json["Name"] = "Software Inventory Collection"; entityPrivileges = { {boost::beast::http::verb::get, {{"Login"}}}, {boost::beast::http::verb::head, {{"Login"}}}, {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; } private: /** * Functions triggers appropriate requests on DBus */ void doGet(crow::response &res, const crow::request &req, const std::vector ¶ms) override { res.json_value = Node::json; // Get sw inventory list, and call the below callback for JSON preparation software_inventory_provider.get_software_inventory_list( [&](const bool &success, const std::vector &output) { if (success) { // ... prepare json array with appropriate @odata.id links nlohmann::json sw_inventory_array = nlohmann::json::array(); for (const std::string &sw_item : output) { sw_inventory_array.push_back( {{"@odata.id", "/redfish/v1/UpdateService/SoftwareInventory/" + sw_item}}); } // Then attach members, count size and return Node::json["Members"] = sw_inventory_array; Node::json["Members@odata.count"] = sw_inventory_array.size(); res.json_value = Node::json; } else { // ... otherwise, return INTERNALL ERROR res.result(boost::beast::http::status::internal_server_error); } res.end(); }); res.end(); } OnDemandSoftwareInventoryProvider software_inventory_provider; }; /** * Chassis override class for delivering Chassis Schema */ class SoftwareInventory : public Node { public: /* * Default Constructor */ template SoftwareInventory(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/SoftwareInventory//", std::string()) { Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory"; Node::json["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory"; Node::json["@odata.context"] = "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory"; Node::json["Name"] = "Software Inventory"; Node::json["Status"] = "OK"; // TODO Node::json["Updateable"] = "No"; entityPrivileges = { {boost::beast::http::verb::get, {{"Login"}}}, {boost::beast::http::verb::head, {{"Login"}}}, {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; } private: /** * Functions triggers appropriate requests on DBus */ void doGet(crow::response &res, const crow::request &req, const std::vector ¶ms) override { if (params.size() != 1) { res.result(boost::beast::http::status::internal_server_error); res.end(); return; } const std::string &sw_id = params[0]; software_inventory_provider.get_software_inventory_data( sw_id, [&, id{std::string(sw_id)} ]( const bool &success, const boost::container::flat_map &output) { res.json_value = Node::json; // If success... if (success) { // prepare all the schema required fields. res.json_value["@odata.id"] = "/redfish/v1/UpdateService/SoftwareInventory/" + id; // also the one from dbus boost::container::flat_map::const_iterator it = output.find("Version"); res.json_value["Version"] = boost::get(it->second); res.json_value["Id"] = id; // prepare respond, and send } else { res.result(boost::beast::http::status::not_found); } res.end(); }); } OnDemandSoftwareInventoryProvider software_inventory_provider; }; } // namespace redfish