1e37f8451SRapkiewicz, Pawel /* 2e37f8451SRapkiewicz, Pawel // Copyright (c) 2018 Intel Corporation 3e37f8451SRapkiewicz, Pawel // 4e37f8451SRapkiewicz, Pawel // Licensed under the Apache License, Version 2.0 (the "License"); 5e37f8451SRapkiewicz, Pawel // you may not use this file except in compliance with the License. 6e37f8451SRapkiewicz, Pawel // You may obtain a copy of the License at 7e37f8451SRapkiewicz, Pawel // 8e37f8451SRapkiewicz, Pawel // http://www.apache.org/licenses/LICENSE-2.0 9e37f8451SRapkiewicz, Pawel // 10e37f8451SRapkiewicz, Pawel // Unless required by applicable law or agreed to in writing, software 11e37f8451SRapkiewicz, Pawel // distributed under the License is distributed on an "AS IS" BASIS, 12e37f8451SRapkiewicz, Pawel // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e37f8451SRapkiewicz, Pawel // See the License for the specific language governing permissions and 14e37f8451SRapkiewicz, Pawel // limitations under the License. 15e37f8451SRapkiewicz, Pawel */ 16e37f8451SRapkiewicz, Pawel #pragma once 17e37f8451SRapkiewicz, Pawel 18e37f8451SRapkiewicz, Pawel #include "node.hpp" 19e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp> 20e37f8451SRapkiewicz, Pawel 21e37f8451SRapkiewicz, Pawel namespace redfish { 22e37f8451SRapkiewicz, Pawel 23e37f8451SRapkiewicz, Pawel /** 24e37f8451SRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 25e37f8451SRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 26e37f8451SRapkiewicz, Pawel */ 27aa2e59c1SEd Tanous // Note, this is not a very useful variant, but because it isn't used to get 28aa2e59c1SEd Tanous // values, it should be as simple as possible 29aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type 30*c5b2abe0SLewanczyk, Dawid using VariantType = sdbusplus::message::variant<bool, std::string>; 31aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair< 32aa2e59c1SEd Tanous sdbusplus::message::object_path, 33aa2e59c1SEd Tanous std::vector<std::pair<std::string, 34aa2e59c1SEd Tanous std::vector<std::pair<std::string, VariantType>>>>>>; 35e37f8451SRapkiewicz, Pawel 36aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>; 37e37f8451SRapkiewicz, Pawel 38e37f8451SRapkiewicz, Pawel /** 39e37f8451SRapkiewicz, Pawel * OnDemandChassisProvider 40274fad5aSGunnar Mills * Chassis provider class that retrieves data directly from dbus, before setting 41e37f8451SRapkiewicz, Pawel * it into JSON output. This does not cache any data. 42e37f8451SRapkiewicz, Pawel * 43e37f8451SRapkiewicz, Pawel * Class can be a good example on how to scale different data providing 44e37f8451SRapkiewicz, Pawel * solutions to produce single schema output. 45e37f8451SRapkiewicz, Pawel * 46e37f8451SRapkiewicz, Pawel * TODO(Pawel) 47e37f8451SRapkiewicz, Pawel * This perhaps shall be different file, which has to be chosen on compile time 48e37f8451SRapkiewicz, Pawel * depending on OEM needs 49e37f8451SRapkiewicz, Pawel */ 50e37f8451SRapkiewicz, Pawel class OnDemandChassisProvider { 51e37f8451SRapkiewicz, Pawel public: 52e37f8451SRapkiewicz, Pawel /** 53e37f8451SRapkiewicz, Pawel * Function that retrieves all Chassis available through EntityManager. 54e37f8451SRapkiewicz, Pawel * @param callback a function that shall be called to convert Dbus output into 55e37f8451SRapkiewicz, Pawel * JSON. 56e37f8451SRapkiewicz, Pawel */ 57e37f8451SRapkiewicz, Pawel template <typename CallbackFunc> 58e37f8451SRapkiewicz, Pawel void get_chassis_list(CallbackFunc &&callback) { 59daf36e2eSEd Tanous const std::array<const char *, 4> interfaces = { 60daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Board", 61daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Chassis", 62daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.PowerSupply", 63daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.System", 64daf36e2eSEd Tanous }; 65e37f8451SRapkiewicz, Pawel crow::connections::system_bus->async_method_call( 66e37f8451SRapkiewicz, Pawel [callback{std::move(callback)}]( 67e37f8451SRapkiewicz, Pawel const boost::system::error_code error_code, 68daf36e2eSEd Tanous const std::vector<std::string> &resp) { 69e37f8451SRapkiewicz, Pawel // Callback requires vector<string> to retrieve all available chassis 70e37f8451SRapkiewicz, Pawel // list. 71e37f8451SRapkiewicz, Pawel std::vector<std::string> chassis_list; 72e37f8451SRapkiewicz, Pawel if (error_code) { 73e37f8451SRapkiewicz, Pawel // Something wrong on DBus, the error_code is not important at this 74e37f8451SRapkiewicz, Pawel // moment, just return success=false, and empty output. Since size 75e37f8451SRapkiewicz, Pawel // of vector may vary depending on information from Entity Manager, 76e37f8451SRapkiewicz, Pawel // and empty output could not be treated same way as error. 77e37f8451SRapkiewicz, Pawel callback(false, chassis_list); 78e37f8451SRapkiewicz, Pawel return; 79e37f8451SRapkiewicz, Pawel } 80e37f8451SRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 81daf36e2eSEd Tanous for (const std::string &objpath : resp) { 82daf36e2eSEd Tanous std::size_t last_pos = objpath.rfind("/"); 83e37f8451SRapkiewicz, Pawel if (last_pos != std::string::npos) { 84e37f8451SRapkiewicz, Pawel // and put it into output vector. 85daf36e2eSEd Tanous chassis_list.emplace_back(objpath.substr(last_pos + 1)); 86e37f8451SRapkiewicz, Pawel } 87e37f8451SRapkiewicz, Pawel } 88274fad5aSGunnar Mills // Finally make a callback with useful data 89e37f8451SRapkiewicz, Pawel callback(true, chassis_list); 90e37f8451SRapkiewicz, Pawel }, 91daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 92daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 93daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 94daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(3), interfaces); 95e37f8451SRapkiewicz, Pawel }; 96e37f8451SRapkiewicz, Pawel }; 97e37f8451SRapkiewicz, Pawel 98e37f8451SRapkiewicz, Pawel /** 99e37f8451SRapkiewicz, Pawel * ChassisCollection derived class for delivering Chassis Collection Schema 100e37f8451SRapkiewicz, Pawel */ 101e37f8451SRapkiewicz, Pawel class ChassisCollection : public Node { 102e37f8451SRapkiewicz, Pawel public: 103e37f8451SRapkiewicz, Pawel template <typename CrowApp> 104e37f8451SRapkiewicz, Pawel ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") { 105e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection"; 106e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 107e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = 108e37f8451SRapkiewicz, Pawel "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 109e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 110e37f8451SRapkiewicz, Pawel 111e0d918bcSEd Tanous entityPrivileges = { 112e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 113e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 114e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 115e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 116e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 117e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 118e37f8451SRapkiewicz, Pawel } 119e37f8451SRapkiewicz, Pawel 120e37f8451SRapkiewicz, Pawel private: 121e37f8451SRapkiewicz, Pawel /** 122e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 123e37f8451SRapkiewicz, Pawel */ 124e37f8451SRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 125e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 126e37f8451SRapkiewicz, Pawel // Get chassis list, and call the below callback for JSON preparation 127e37f8451SRapkiewicz, Pawel chassis_provider.get_chassis_list( 128e37f8451SRapkiewicz, Pawel [&](const bool &success, const std::vector<std::string> &output) { 129e37f8451SRapkiewicz, Pawel if (success) { 130e37f8451SRapkiewicz, Pawel // ... prepare json array with appropriate @odata.id links 131e37f8451SRapkiewicz, Pawel nlohmann::json chassis_array = nlohmann::json::array(); 132e37f8451SRapkiewicz, Pawel for (const std::string &chassis_item : output) { 133e37f8451SRapkiewicz, Pawel chassis_array.push_back( 134e37f8451SRapkiewicz, Pawel {{"@odata.id", "/redfish/v1/Chassis/" + chassis_item}}); 135e37f8451SRapkiewicz, Pawel } 136e37f8451SRapkiewicz, Pawel // Then attach members, count size and return, 137e37f8451SRapkiewicz, Pawel Node::json["Members"] = chassis_array; 138e37f8451SRapkiewicz, Pawel Node::json["Members@odata.count"] = chassis_array.size(); 139e37f8451SRapkiewicz, Pawel res.json_value = Node::json; 140e37f8451SRapkiewicz, Pawel } else { 141e37f8451SRapkiewicz, Pawel // ... otherwise, return INTERNALL ERROR 142e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 143e37f8451SRapkiewicz, Pawel } 144e37f8451SRapkiewicz, Pawel res.end(); 145e37f8451SRapkiewicz, Pawel }); 146e37f8451SRapkiewicz, Pawel } 147e37f8451SRapkiewicz, Pawel 148e37f8451SRapkiewicz, Pawel // Chassis Provider object 149e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 150e37f8451SRapkiewicz, Pawel OnDemandChassisProvider chassis_provider; 151e37f8451SRapkiewicz, Pawel }; 152e37f8451SRapkiewicz, Pawel 153e37f8451SRapkiewicz, Pawel /** 154e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 155e37f8451SRapkiewicz, Pawel */ 156e37f8451SRapkiewicz, Pawel class Chassis : public Node { 157e37f8451SRapkiewicz, Pawel public: 158e37f8451SRapkiewicz, Pawel /* 159e37f8451SRapkiewicz, Pawel * Default Constructor 160e37f8451SRapkiewicz, Pawel */ 161e37f8451SRapkiewicz, Pawel template <typename CrowApp> 162e37f8451SRapkiewicz, Pawel Chassis(CrowApp &app) 163e37f8451SRapkiewicz, Pawel : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) { 164e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 165e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 166e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis"; 167e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 1686c233015SEd Tanous Node::json["ChassisType"] = "RackMount"; 169e37f8451SRapkiewicz, Pawel 170e0d918bcSEd Tanous entityPrivileges = { 171e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 172e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 173e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 174e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 175e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 176e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 177e37f8451SRapkiewicz, Pawel } 178e37f8451SRapkiewicz, Pawel 179e37f8451SRapkiewicz, Pawel private: 180e37f8451SRapkiewicz, Pawel /** 181e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 182e37f8451SRapkiewicz, Pawel */ 183e37f8451SRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 184e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 185e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 186e37f8451SRapkiewicz, Pawel // impossible. 187e37f8451SRapkiewicz, Pawel if (params.size() != 1) { 188e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 189e37f8451SRapkiewicz, Pawel res.end(); 190e37f8451SRapkiewicz, Pawel return; 191e37f8451SRapkiewicz, Pawel } 192e37f8451SRapkiewicz, Pawel 193daf36e2eSEd Tanous res.json_value = Node::json; 194daf36e2eSEd Tanous const std::string &chassis_id = params[0]; 195daf36e2eSEd Tanous crow::connections::system_bus->async_method_call( 196daf36e2eSEd Tanous [&res, chassis_id(std::string(chassis_id)) ]( 197daf36e2eSEd Tanous const boost::system::error_code error_code, 198daf36e2eSEd Tanous const std::vector<std::pair< 199daf36e2eSEd Tanous std::string, 200daf36e2eSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>>> 201daf36e2eSEd Tanous &subtree) { 202daf36e2eSEd Tanous if (error_code) { 203daf36e2eSEd Tanous res.json_value = {}; 204e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 205e37f8451SRapkiewicz, Pawel res.end(); 206daf36e2eSEd Tanous return; 207daf36e2eSEd Tanous } 208daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 209daf36e2eSEd Tanous for (const std::pair<std::string, 210daf36e2eSEd Tanous std::vector<std::pair<std::string, 211daf36e2eSEd Tanous std::vector<std::string>>>> 212daf36e2eSEd Tanous &object : subtree) { 213daf36e2eSEd Tanous const std::string &path = object.first; 214daf36e2eSEd Tanous const std::vector<std::pair<std::string, std::vector<std::string>>> 215daf36e2eSEd Tanous &connectionNames = object.second; 216e0d918bcSEd Tanous 217daf36e2eSEd Tanous if (!boost::ends_with(path, chassis_id)) { 218daf36e2eSEd Tanous continue; 219daf36e2eSEd Tanous } 220daf36e2eSEd Tanous if (connectionNames.size() < 1) { 221e0d918bcSEd Tanous CROW_LOG_ERROR << "Only got " << connectionNames.size() 222e0d918bcSEd Tanous << " connection names"; 223e0d918bcSEd Tanous continue; 224daf36e2eSEd Tanous } 225e0d918bcSEd Tanous 226daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 227daf36e2eSEd Tanous crow::connections::system_bus->async_method_call( 228daf36e2eSEd Tanous [&res, chassis_id(std::string(chassis_id)) ]( 229daf36e2eSEd Tanous const boost::system::error_code error_code, 230daf36e2eSEd Tanous const std::vector<std::pair<std::string, VariantType>> 231daf36e2eSEd Tanous &propertiesList) { 232daf36e2eSEd Tanous for (const std::pair<std::string, VariantType> &property : 233daf36e2eSEd Tanous propertiesList) { 234daf36e2eSEd Tanous const std::string *value = 235daf36e2eSEd Tanous mapbox::get_ptr<const std::string>(property.second); 236daf36e2eSEd Tanous if (value != nullptr) { 237daf36e2eSEd Tanous res.json_value[property.first] = *value; 238daf36e2eSEd Tanous } 239daf36e2eSEd Tanous } 240daf36e2eSEd Tanous res.json_value["Name"] = chassis_id; 241daf36e2eSEd Tanous res.json_value["Thermal"] = { 242daf36e2eSEd Tanous {"@odata.id", 243daf36e2eSEd Tanous "/redfish/v1/Chassis/" + chassis_id + "/Thermal"}}; 244daf36e2eSEd Tanous res.end(); 245daf36e2eSEd Tanous }, 246daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 247daf36e2eSEd Tanous "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); 248daf36e2eSEd Tanous // Found the connection we were looking for, return 249daf36e2eSEd Tanous return; 250daf36e2eSEd Tanous } 251e0d918bcSEd Tanous 252daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 253e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 254e0d918bcSEd Tanous 255daf36e2eSEd Tanous res.end(); 256daf36e2eSEd Tanous }, 257daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 258daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 259daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 260daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(0), 261daf36e2eSEd Tanous std::array<const char *, 1>{ 262daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"}); 263e37f8451SRapkiewicz, Pawel } 264e37f8451SRapkiewicz, Pawel 265e37f8451SRapkiewicz, Pawel // Chassis Provider object 266e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 267e37f8451SRapkiewicz, Pawel OnDemandChassisProvider chassis_provider; 268e0d918bcSEd Tanous }; // namespace redfish 269e37f8451SRapkiewicz, Pawel 270e37f8451SRapkiewicz, Pawel } // namespace redfish 271