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 */ 2755c7b7a2SEd 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 30c5b2abe0SLewanczyk, 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> 5855c7b7a2SEd Tanous void getChassisList(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 }; 6555c7b7a2SEd Tanous crow::connections::systemBus->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. 7155c7b7a2SEd Tanous std::vector<std::string> chassisList; 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. 7755c7b7a2SEd Tanous callback(false, chassisList); 78e37f8451SRapkiewicz, Pawel return; 79e37f8451SRapkiewicz, Pawel } 80e37f8451SRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 81daf36e2eSEd Tanous for (const std::string &objpath : resp) { 8255c7b7a2SEd Tanous std::size_t lastPos = objpath.rfind("/"); 8355c7b7a2SEd Tanous if (lastPos != std::string::npos) { 84e37f8451SRapkiewicz, Pawel // and put it into output vector. 8555c7b7a2SEd Tanous chassisList.emplace_back(objpath.substr(lastPos + 1)); 86e37f8451SRapkiewicz, Pawel } 87e37f8451SRapkiewicz, Pawel } 88*a434f2bdSEd Tanous // Finally make a callback with useful data 8955c7b7a2SEd Tanous callback(true, chassisList); 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 ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") { 104e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection"; 105e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 106e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = 107e37f8451SRapkiewicz, Pawel "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 108e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 109e37f8451SRapkiewicz, Pawel 110e0d918bcSEd Tanous entityPrivileges = { 111e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 112e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 113e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 114e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 115e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 116e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 117e37f8451SRapkiewicz, Pawel } 118e37f8451SRapkiewicz, Pawel 119e37f8451SRapkiewicz, Pawel private: 120e37f8451SRapkiewicz, Pawel /** 121e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 122e37f8451SRapkiewicz, Pawel */ 12355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 124e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 12555c7b7a2SEd Tanous // get chassis list, and call the below callback for JSON preparation 12655c7b7a2SEd Tanous chassisProvider.getChassisList( 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 13055c7b7a2SEd Tanous nlohmann::json chassisArray = nlohmann::json::array(); 13155c7b7a2SEd Tanous for (const std::string &chassisItem : output) { 13255c7b7a2SEd Tanous chassisArray.push_back( 13355c7b7a2SEd Tanous {{"@odata.id", "/redfish/v1/Chassis/" + chassisItem}}); 134e37f8451SRapkiewicz, Pawel } 135e37f8451SRapkiewicz, Pawel // Then attach members, count size and return, 13655c7b7a2SEd Tanous Node::json["Members"] = chassisArray; 13755c7b7a2SEd Tanous Node::json["Members@odata.count"] = chassisArray.size(); 13855c7b7a2SEd Tanous res.jsonValue = Node::json; 139e37f8451SRapkiewicz, Pawel } else { 140e37f8451SRapkiewicz, Pawel // ... otherwise, return INTERNALL ERROR 141e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_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 14955c7b7a2SEd Tanous OnDemandChassisProvider chassisProvider; 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 Chassis(CrowApp &app) 158e37f8451SRapkiewicz, Pawel : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) { 159e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 160e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 161e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis"; 162e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 1636c233015SEd Tanous Node::json["ChassisType"] = "RackMount"; 164e37f8451SRapkiewicz, Pawel 165e0d918bcSEd Tanous entityPrivileges = { 166e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 167e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 168e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 169e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 170e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 171e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 172e37f8451SRapkiewicz, Pawel } 173e37f8451SRapkiewicz, Pawel 174e37f8451SRapkiewicz, Pawel private: 175e37f8451SRapkiewicz, Pawel /** 176e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 177e37f8451SRapkiewicz, Pawel */ 17855c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 179e37f8451SRapkiewicz, Pawel const std::vector<std::string> ¶ms) override { 180e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 181e37f8451SRapkiewicz, Pawel // impossible. 182e37f8451SRapkiewicz, Pawel if (params.size() != 1) { 183e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 184e37f8451SRapkiewicz, Pawel res.end(); 185e37f8451SRapkiewicz, Pawel return; 186e37f8451SRapkiewicz, Pawel } 187e37f8451SRapkiewicz, Pawel 18855c7b7a2SEd Tanous res.jsonValue = Node::json; 18955c7b7a2SEd Tanous const std::string &chassisId = params[0]; 19055c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 19155c7b7a2SEd Tanous [&res, chassisId(std::string(chassisId)) ]( 192daf36e2eSEd Tanous const boost::system::error_code error_code, 193daf36e2eSEd Tanous const std::vector<std::pair< 194daf36e2eSEd Tanous std::string, 195daf36e2eSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>>> 196daf36e2eSEd Tanous &subtree) { 197daf36e2eSEd Tanous if (error_code) { 19855c7b7a2SEd Tanous res.jsonValue = {}; 199e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 200e37f8451SRapkiewicz, Pawel res.end(); 201daf36e2eSEd Tanous return; 202daf36e2eSEd Tanous } 203daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 204daf36e2eSEd Tanous for (const std::pair<std::string, 205daf36e2eSEd Tanous std::vector<std::pair<std::string, 206daf36e2eSEd Tanous std::vector<std::string>>>> 207daf36e2eSEd Tanous &object : subtree) { 208daf36e2eSEd Tanous const std::string &path = object.first; 209daf36e2eSEd Tanous const std::vector<std::pair<std::string, std::vector<std::string>>> 210daf36e2eSEd Tanous &connectionNames = object.second; 211e0d918bcSEd Tanous 21255c7b7a2SEd Tanous if (!boost::ends_with(path, chassisId)) { 213daf36e2eSEd Tanous continue; 214daf36e2eSEd Tanous } 215daf36e2eSEd Tanous if (connectionNames.size() < 1) { 21655c7b7a2SEd Tanous BMCWEB_LOG_ERROR << "Only got " << connectionNames.size() 21755c7b7a2SEd Tanous << " Connection names"; 218e0d918bcSEd Tanous continue; 219daf36e2eSEd Tanous } 220e0d918bcSEd Tanous 221daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 22255c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 22355c7b7a2SEd Tanous [&res, chassisId(std::string(chassisId)) ]( 224daf36e2eSEd Tanous const boost::system::error_code error_code, 225daf36e2eSEd Tanous const std::vector<std::pair<std::string, VariantType>> 226daf36e2eSEd Tanous &propertiesList) { 227daf36e2eSEd Tanous for (const std::pair<std::string, VariantType> &property : 228daf36e2eSEd Tanous propertiesList) { 229daf36e2eSEd Tanous const std::string *value = 23055c7b7a2SEd Tanous mapbox::getPtr<const std::string>(property.second); 231daf36e2eSEd Tanous if (value != nullptr) { 23255c7b7a2SEd Tanous res.jsonValue[property.first] = *value; 233daf36e2eSEd Tanous } 234daf36e2eSEd Tanous } 23555c7b7a2SEd Tanous res.jsonValue["Name"] = chassisId; 23655c7b7a2SEd Tanous res.jsonValue["Id"] = chassisId; 23755c7b7a2SEd Tanous res.jsonValue["Thermal"] = { 238daf36e2eSEd Tanous {"@odata.id", 23955c7b7a2SEd Tanous "/redfish/v1/Chassis/" + chassisId + "/Thermal"}}; 240daf36e2eSEd Tanous res.end(); 241daf36e2eSEd Tanous }, 242daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 243daf36e2eSEd Tanous "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); 24455c7b7a2SEd Tanous // Found the Connection we were looking for, return 245daf36e2eSEd Tanous return; 246daf36e2eSEd Tanous } 247e0d918bcSEd Tanous 248daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 249e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 250e0d918bcSEd Tanous 251daf36e2eSEd Tanous res.end(); 252daf36e2eSEd Tanous }, 253daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 254daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 255daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 256daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(0), 257daf36e2eSEd Tanous std::array<const char *, 1>{ 258daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"}); 259e37f8451SRapkiewicz, Pawel } 260e37f8451SRapkiewicz, Pawel 261e37f8451SRapkiewicz, Pawel // Chassis Provider object 262e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 26355c7b7a2SEd Tanous OnDemandChassisProvider chassisProvider; 264e0d918bcSEd Tanous }; // namespace redfish 265e37f8451SRapkiewicz, Pawel 266e37f8451SRapkiewicz, Pawel } // namespace redfish 267