diff options
| author | Jennifer Lee <jennifer1.lee@intel.com> | 2018-04-24 15:59:34 -0700 |
|---|---|---|
| committer | Ed Tanous <ed.tanous@intel.com> | 2018-06-29 18:49:09 +0000 |
| commit | 729dae72826e58134ca4e49587427703ad0286db (patch) | |
| tree | c3f376786bce65a7838878dc7e14bf8077b6660e | |
| parent | a4e18f2a2b1652b378bf2e182a13595e05e66881 (diff) | |
| download | bmcweb-729dae72826e58134ca4e49587427703ad0286db.tar.gz bmcweb-729dae72826e58134ca4e49587427703ad0286db.zip | |
Added UpdateService to Redfish
- Implemented SoftwareInventoryCollection
- Implemented SoftwareInventory
Currently DBus supports BMC FW version only, so only BMC is listed in
the invetory.
Change-Id: I28a151b2b1cd98573ec93234717eae5eaf95058c
Signed-off-by: Jennifer Lee <jennifer1.lee@intel.com>
| -rw-r--r-- | redfish-core/include/redfish.hpp | 9 | ||||
| -rw-r--r-- | redfish-core/lib/update_service.hpp | 289 |
2 files changed, 295 insertions, 3 deletions
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index aa25a44..835cc5d 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -16,14 +16,15 @@ #pragma once #include "../lib/account_service.hpp" +#include "../lib/chassis.hpp" +#include "../lib/ethernet.hpp" #include "../lib/managers.hpp" #include "../lib/network_protocol.hpp" #include "../lib/redfish_sessions.hpp" #include "../lib/roles.hpp" #include "../lib/service_root.hpp" -#include "../lib/ethernet.hpp" #include "../lib/thermal.hpp" -#include "../lib/chassis.hpp" +#include "../lib/update_service.hpp" #include "webserver_common.hpp" namespace redfish { @@ -53,7 +54,9 @@ class RedfishService { nodes.emplace_back(std::make_unique<ManagerCollection>(app)); nodes.emplace_back(std::make_unique<ChassisCollection>(app)); nodes.emplace_back(std::make_unique<Chassis>(app)); - + nodes.emplace_back(std::make_unique<UpdateService>(app)); + nodes.emplace_back(std::make_unique<SoftwareInventoryCollection>(app)); + nodes.emplace_back(std::make_unique<SoftwareInventory>(app)); for (auto& node : nodes) { node->getSubRoutes(nodes); } diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp new file mode 100644 index 0000000..21efbd5 --- /dev/null +++ b/redfish-core/lib/update_service.hpp @@ -0,0 +1,289 @@ +/* +// 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 <boost/container/flat_map.hpp> + +namespace redfish { + +class OnDemandSoftwareInventoryProvider { + public: + template <typename CallbackFunc> + 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<std::pair< + std::string, + std::vector<std::pair<std::string, std::vector<std::string>>>>> + &subtree) { + + std::vector<boost::container::flat_map<std::string, std::string>> + 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<std::pair<std::string, std::vector<std::string>>> + &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<std::pair<std::string, VariantType>> + &propertiesList) { + for (auto &property : propertiesList) { + boost::container::flat_map<std::string, std::string> + single_sw_item_properties; + single_sw_item_properties[property.first] = + *(mapbox::get_ptr<const std::string>(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<const char *, 1>{"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 <typename CallbackFunc> + void get_software_inventory_list(CallbackFunc &&callback) { + get_all_software_inventory_data( + [callback]( + const bool &success, + const std::vector< + boost::container::flat_map<std::string, std::string>> &output) { + std::vector<std::string> sw_inv_list; + for (auto &i : output) { + boost::container::flat_map<std::string, std::string>::const_iterator + p = i.find("Purpose"); + if ((p != i.end())) { + const std::string &sw_inv_purpose = + boost::get<std::string>(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 <typename CallbackFunc> + 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<std::string, std::string>> &output) { + for (auto &i : output) { + boost::container::flat_map<std::string, std::string>::const_iterator + p = i.find("Purpose"); + // Find the one with Purpose matching res_name + if ((p != i.end()) && + boost::ends_with(boost::get<std::string>(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<std::string> ¶ms) override { + res.json_value = Node::json; + res.end(); + } +}; + +class SoftwareInventoryCollection : public Node { + public: + /* + * Default Constructor + */ + template <typename CrowApp> + 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<std::string> ¶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<std::string> &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 <typename CrowApp> + SoftwareInventory(CrowApp &app) + : Node(app, "/redfish/v1/UpdateService/SoftwareInventory/<str>/", + 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<std::string> ¶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<std::string, std::string> + &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<std::string, std::string>::const_iterator + it = output.find("Version"); + res.json_value["Version"] = boost::get<std::string>(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 |

