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 30aa2e59c1SEd Tanous using VariantType = sdbusplus::message::variant<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) { 59*daf36e2eSEd Tanous const std::array<const char *, 4> interfaces = { 60*daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Board", 61*daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Chassis", 62*daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.PowerSupply", 63*daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.System", 64*daf36e2eSEd 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, 68*daf36e2eSEd 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. 81*daf36e2eSEd Tanous for (const std::string &objpath : resp) { 82*daf36e2eSEd Tanous std::size_t last_pos = objpath.rfind("/"); 83e37f8451SRapkiewicz, Pawel if (last_pos != std::string::npos) { 84e37f8451SRapkiewicz, Pawel // and put it into output vector. 85*daf36e2eSEd 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 }, 91*daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 92*daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 93*daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 94*daf36e2eSEd 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 111e37f8451SRapkiewicz, Pawel entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}}, 112e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::HEAD, {{"Login"}}}, 113e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}}, 114e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}}, 115e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}}, 116e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}}; 117e37f8451SRapkiewicz, Pawel } 118e37f8451SRapkiewicz, Pawel 119e37f8451SRapkiewicz, Pawel private: 120e37f8451SRapkiewicz, Pawel /** 121e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 122e37f8451SRapkiewicz, Pawel */ 123e37f8451SRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 124e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 125e37f8451SRapkiewicz, Pawel // Get chassis list, and call the below callback for JSON preparation 126e37f8451SRapkiewicz, Pawel chassis_provider.get_chassis_list( 127e37f8451SRapkiewicz, Pawel [&](const bool &success, const std::vector<std::string> &output) { 128e37f8451SRapkiewicz, Pawel if (success) { 129e37f8451SRapkiewicz, Pawel // ... prepare json array with appropriate @odata.id links 130e37f8451SRapkiewicz, Pawel nlohmann::json chassis_array = nlohmann::json::array(); 131e37f8451SRapkiewicz, Pawel for (const std::string &chassis_item : output) { 132e37f8451SRapkiewicz, Pawel chassis_array.push_back( 133e37f8451SRapkiewicz, Pawel {{"@odata.id", "/redfish/v1/Chassis/" + chassis_item}}); 134e37f8451SRapkiewicz, Pawel } 135e37f8451SRapkiewicz, Pawel // Then attach members, count size and return, 136e37f8451SRapkiewicz, Pawel Node::json["Members"] = chassis_array; 137e37f8451SRapkiewicz, Pawel Node::json["Members@odata.count"] = chassis_array.size(); 138e37f8451SRapkiewicz, Pawel res.json_value = Node::json; 139e37f8451SRapkiewicz, Pawel } else { 140e37f8451SRapkiewicz, Pawel // ... otherwise, return INTERNALL ERROR 141e37f8451SRapkiewicz, Pawel res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); 142e37f8451SRapkiewicz, Pawel } 143e37f8451SRapkiewicz, Pawel res.end(); 144e37f8451SRapkiewicz, Pawel }); 145e37f8451SRapkiewicz, Pawel } 146e37f8451SRapkiewicz, Pawel 147e37f8451SRapkiewicz, Pawel // Chassis Provider object 148e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 149e37f8451SRapkiewicz, Pawel OnDemandChassisProvider chassis_provider; 150e37f8451SRapkiewicz, Pawel }; 151e37f8451SRapkiewicz, Pawel 152e37f8451SRapkiewicz, Pawel /** 153e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 154e37f8451SRapkiewicz, Pawel */ 155e37f8451SRapkiewicz, Pawel class Chassis : public Node { 156e37f8451SRapkiewicz, Pawel public: 157e37f8451SRapkiewicz, Pawel /* 158e37f8451SRapkiewicz, Pawel * Default Constructor 159e37f8451SRapkiewicz, Pawel */ 160e37f8451SRapkiewicz, Pawel template <typename CrowApp> 161e37f8451SRapkiewicz, Pawel Chassis(CrowApp &app) 162e37f8451SRapkiewicz, Pawel : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) { 163e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 164e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 165e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis"; 166e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 1676c233015SEd Tanous Node::json["ChassisType"] = "RackMount"; 168e37f8451SRapkiewicz, Pawel 169e37f8451SRapkiewicz, Pawel entityPrivileges = {{crow::HTTPMethod::GET, {{"Login"}}}, 170e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::HEAD, {{"Login"}}}, 171e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::PATCH, {{"ConfigureComponents"}}}, 172e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::PUT, {{"ConfigureComponents"}}}, 173e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::DELETE, {{"ConfigureComponents"}}}, 174e37f8451SRapkiewicz, Pawel {crow::HTTPMethod::POST, {{"ConfigureComponents"}}}}; 175e37f8451SRapkiewicz, Pawel } 176e37f8451SRapkiewicz, Pawel 177e37f8451SRapkiewicz, Pawel private: 178e37f8451SRapkiewicz, Pawel /** 179e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 180e37f8451SRapkiewicz, Pawel */ 181e37f8451SRapkiewicz, Pawel void doGet(crow::response &res, const crow::request &req, 182e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 183e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 184e37f8451SRapkiewicz, Pawel // impossible. 185e37f8451SRapkiewicz, Pawel if (params.size() != 1) { 186e37f8451SRapkiewicz, Pawel res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); 187e37f8451SRapkiewicz, Pawel res.end(); 188e37f8451SRapkiewicz, Pawel return; 189e37f8451SRapkiewicz, Pawel } 190e37f8451SRapkiewicz, Pawel 191*daf36e2eSEd Tanous res.json_value = Node::json; 192*daf36e2eSEd Tanous const std::string &chassis_id = params[0]; 193*daf36e2eSEd Tanous crow::connections::system_bus->async_method_call( 194*daf36e2eSEd Tanous [&res, chassis_id(std::string(chassis_id)) ]( 195*daf36e2eSEd Tanous const boost::system::error_code error_code, 196*daf36e2eSEd Tanous const std::vector<std::pair< 197*daf36e2eSEd Tanous std::string, 198*daf36e2eSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>>> 199*daf36e2eSEd Tanous &subtree) { 200*daf36e2eSEd Tanous if (error_code) { 201*daf36e2eSEd Tanous res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); 202*daf36e2eSEd Tanous res.json_value = {}; 203e37f8451SRapkiewicz, Pawel res.end(); 204*daf36e2eSEd Tanous return; 205*daf36e2eSEd Tanous } 206*daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 207*daf36e2eSEd Tanous for (const std::pair<std::string, 208*daf36e2eSEd Tanous std::vector<std::pair<std::string, 209*daf36e2eSEd Tanous std::vector<std::string>>>> 210*daf36e2eSEd Tanous &object : subtree) { 211*daf36e2eSEd Tanous const std::string &path = object.first; 212*daf36e2eSEd Tanous const std::vector<std::pair<std::string, std::vector<std::string>>> 213*daf36e2eSEd Tanous &connectionNames = object.second; 214*daf36e2eSEd Tanous if (!boost::ends_with(path, chassis_id)) { 215*daf36e2eSEd Tanous continue; 216*daf36e2eSEd Tanous } 217*daf36e2eSEd Tanous if (connectionNames.size() < 1) { 218*daf36e2eSEd Tanous res.code = static_cast<int>(HttpRespCode::INTERNAL_ERROR); 219*daf36e2eSEd Tanous res.end(); 220*daf36e2eSEd Tanous return; 221*daf36e2eSEd Tanous } 222*daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 223*daf36e2eSEd Tanous crow::connections::system_bus->async_method_call( 224*daf36e2eSEd Tanous [&res, chassis_id(std::string(chassis_id)) ]( 225*daf36e2eSEd Tanous const boost::system::error_code error_code, 226*daf36e2eSEd Tanous const std::vector<std::pair<std::string, VariantType>> 227*daf36e2eSEd Tanous &propertiesList) { 228*daf36e2eSEd Tanous for (const std::pair<std::string, VariantType> &property : 229*daf36e2eSEd Tanous propertiesList) { 230*daf36e2eSEd Tanous const std::string *value = 231*daf36e2eSEd Tanous mapbox::get_ptr<const std::string>(property.second); 232*daf36e2eSEd Tanous if (value != nullptr) { 233*daf36e2eSEd Tanous res.json_value[property.first] = *value; 234*daf36e2eSEd Tanous } 235*daf36e2eSEd Tanous } 236*daf36e2eSEd Tanous res.json_value["Name"] = chassis_id; 237*daf36e2eSEd Tanous res.json_value["Thermal"] = { 238*daf36e2eSEd Tanous {"@odata.id", 239*daf36e2eSEd Tanous "/redfish/v1/Chassis/" + chassis_id + "/Thermal"}}; 240*daf36e2eSEd Tanous res.end(); 241*daf36e2eSEd Tanous }, 242*daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 243*daf36e2eSEd Tanous "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); 244*daf36e2eSEd Tanous // Found the connection we were looking for, return 245*daf36e2eSEd Tanous return; 246*daf36e2eSEd Tanous } 247*daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 248*daf36e2eSEd Tanous res.code = static_cast<int>(HttpRespCode::NOT_FOUND); 249*daf36e2eSEd Tanous res.end(); 250*daf36e2eSEd Tanous }, 251*daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 252*daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 253*daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 254*daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(0), 255*daf36e2eSEd Tanous std::array<const char *, 1>{ 256*daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"}); 257e37f8451SRapkiewicz, Pawel } 258e37f8451SRapkiewicz, Pawel 259e37f8451SRapkiewicz, Pawel // Chassis Provider object 260e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 261e37f8451SRapkiewicz, Pawel OnDemandChassisProvider chassis_provider; 262e37f8451SRapkiewicz, Pawel }; 263e37f8451SRapkiewicz, Pawel 264e37f8451SRapkiewicz, Pawel } // namespace redfish 265