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" 19*1abe55efSEd Tanous 20e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp> 21e37f8451SRapkiewicz, Pawel 22*1abe55efSEd Tanous namespace redfish 23*1abe55efSEd Tanous { 24e37f8451SRapkiewicz, Pawel 25e37f8451SRapkiewicz, Pawel /** 26e37f8451SRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 27e37f8451SRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 28e37f8451SRapkiewicz, Pawel */ 2955c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get 30aa2e59c1SEd Tanous // values, it should be as simple as possible 31aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type 32c5b2abe0SLewanczyk, Dawid using VariantType = sdbusplus::message::variant<bool, std::string>; 33aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair< 34aa2e59c1SEd Tanous sdbusplus::message::object_path, 35aa2e59c1SEd Tanous std::vector<std::pair<std::string, 36aa2e59c1SEd Tanous std::vector<std::pair<std::string, VariantType>>>>>>; 37e37f8451SRapkiewicz, Pawel 38aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>; 39e37f8451SRapkiewicz, Pawel 40e37f8451SRapkiewicz, Pawel /** 41e37f8451SRapkiewicz, Pawel * OnDemandChassisProvider 42274fad5aSGunnar Mills * Chassis provider class that retrieves data directly from dbus, before setting 43e37f8451SRapkiewicz, Pawel * it into JSON output. This does not cache any data. 44e37f8451SRapkiewicz, Pawel * 45e37f8451SRapkiewicz, Pawel * Class can be a good example on how to scale different data providing 46e37f8451SRapkiewicz, Pawel * solutions to produce single schema output. 47e37f8451SRapkiewicz, Pawel * 48e37f8451SRapkiewicz, Pawel * TODO(Pawel) 49e37f8451SRapkiewicz, Pawel * This perhaps shall be different file, which has to be chosen on compile time 50e37f8451SRapkiewicz, Pawel * depending on OEM needs 51e37f8451SRapkiewicz, Pawel */ 52*1abe55efSEd Tanous class OnDemandChassisProvider 53*1abe55efSEd Tanous { 54e37f8451SRapkiewicz, Pawel public: 55e37f8451SRapkiewicz, Pawel /** 56e37f8451SRapkiewicz, Pawel * Function that retrieves all Chassis available through EntityManager. 57*1abe55efSEd Tanous * @param callback a function that shall be called to convert Dbus output 58*1abe55efSEd Tanous * into JSON. 59e37f8451SRapkiewicz, Pawel */ 60e37f8451SRapkiewicz, Pawel template <typename CallbackFunc> 61*1abe55efSEd Tanous void getChassisList(CallbackFunc &&callback) 62*1abe55efSEd Tanous { 63daf36e2eSEd Tanous const std::array<const char *, 4> interfaces = { 64daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Board", 65daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.Chassis", 66daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.PowerSupply", 67daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Item.System", 68daf36e2eSEd Tanous }; 6955c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 70e37f8451SRapkiewicz, Pawel [callback{std::move(callback)}]( 71e37f8451SRapkiewicz, Pawel const boost::system::error_code error_code, 72daf36e2eSEd Tanous const std::vector<std::string> &resp) { 73*1abe55efSEd Tanous // Callback requires vector<string> to retrieve all available 74*1abe55efSEd Tanous // chassis list. 7555c7b7a2SEd Tanous std::vector<std::string> chassisList; 76*1abe55efSEd Tanous if (error_code) 77*1abe55efSEd Tanous { 78*1abe55efSEd Tanous // Something wrong on DBus, the error_code is not important 79*1abe55efSEd Tanous // at this moment, just return success=false, and empty 80*1abe55efSEd Tanous // output. Since size of vector may vary depending on 81*1abe55efSEd Tanous // information from Entity Manager, and empty output could 82*1abe55efSEd Tanous // not be treated same way as error. 8355c7b7a2SEd Tanous callback(false, chassisList); 84e37f8451SRapkiewicz, Pawel return; 85e37f8451SRapkiewicz, Pawel } 86e37f8451SRapkiewicz, Pawel // Iterate over all retrieved ObjectPaths. 87*1abe55efSEd Tanous for (const std::string &objpath : resp) 88*1abe55efSEd Tanous { 8955c7b7a2SEd Tanous std::size_t lastPos = objpath.rfind("/"); 90*1abe55efSEd Tanous if (lastPos != std::string::npos) 91*1abe55efSEd Tanous { 92e37f8451SRapkiewicz, Pawel // and put it into output vector. 9355c7b7a2SEd Tanous chassisList.emplace_back(objpath.substr(lastPos + 1)); 94e37f8451SRapkiewicz, Pawel } 95e37f8451SRapkiewicz, Pawel } 96a434f2bdSEd Tanous // Finally make a callback with useful data 9755c7b7a2SEd Tanous callback(true, chassisList); 98e37f8451SRapkiewicz, Pawel }, 99daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 100daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 101daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 102daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(3), interfaces); 103e37f8451SRapkiewicz, Pawel }; 104e37f8451SRapkiewicz, Pawel }; 105e37f8451SRapkiewicz, Pawel 106e37f8451SRapkiewicz, Pawel /** 107e37f8451SRapkiewicz, Pawel * ChassisCollection derived class for delivering Chassis Collection Schema 108e37f8451SRapkiewicz, Pawel */ 109*1abe55efSEd Tanous class ChassisCollection : public Node 110*1abe55efSEd Tanous { 111e37f8451SRapkiewicz, Pawel public: 112*1abe55efSEd Tanous ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") 113*1abe55efSEd Tanous { 114e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection"; 115e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 116e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = 117e37f8451SRapkiewicz, Pawel "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 118e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 119e37f8451SRapkiewicz, Pawel 120e0d918bcSEd Tanous entityPrivileges = { 121e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 122e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 123e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 124e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 125e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 126e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 127e37f8451SRapkiewicz, Pawel } 128e37f8451SRapkiewicz, Pawel 129e37f8451SRapkiewicz, Pawel private: 130e37f8451SRapkiewicz, Pawel /** 131e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 132e37f8451SRapkiewicz, Pawel */ 13355c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 134*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 135*1abe55efSEd Tanous { 13655c7b7a2SEd Tanous // get chassis list, and call the below callback for JSON preparation 13755c7b7a2SEd Tanous chassisProvider.getChassisList( 138e37f8451SRapkiewicz, Pawel [&](const bool &success, const std::vector<std::string> &output) { 139*1abe55efSEd Tanous if (success) 140*1abe55efSEd Tanous { 141e37f8451SRapkiewicz, Pawel // ... prepare json array with appropriate @odata.id links 14255c7b7a2SEd Tanous nlohmann::json chassisArray = nlohmann::json::array(); 143*1abe55efSEd Tanous for (const std::string &chassisItem : output) 144*1abe55efSEd Tanous { 14555c7b7a2SEd Tanous chassisArray.push_back( 146*1abe55efSEd Tanous {{"@odata.id", 147*1abe55efSEd Tanous "/redfish/v1/Chassis/" + chassisItem}}); 148e37f8451SRapkiewicz, Pawel } 149e37f8451SRapkiewicz, Pawel // Then attach members, count size and return, 15055c7b7a2SEd Tanous Node::json["Members"] = chassisArray; 15155c7b7a2SEd Tanous Node::json["Members@odata.count"] = chassisArray.size(); 15255c7b7a2SEd Tanous res.jsonValue = Node::json; 153*1abe55efSEd Tanous } 154*1abe55efSEd Tanous else 155*1abe55efSEd Tanous { 156e37f8451SRapkiewicz, Pawel // ... otherwise, return INTERNALL ERROR 157*1abe55efSEd Tanous res.result( 158*1abe55efSEd Tanous boost::beast::http::status::internal_server_error); 159e37f8451SRapkiewicz, Pawel } 160e37f8451SRapkiewicz, Pawel res.end(); 161e37f8451SRapkiewicz, Pawel }); 162e37f8451SRapkiewicz, Pawel } 163e37f8451SRapkiewicz, Pawel 164e37f8451SRapkiewicz, Pawel // Chassis Provider object 165e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 16655c7b7a2SEd Tanous OnDemandChassisProvider chassisProvider; 167e37f8451SRapkiewicz, Pawel }; 168e37f8451SRapkiewicz, Pawel 169e37f8451SRapkiewicz, Pawel /** 170e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 171e37f8451SRapkiewicz, Pawel */ 172*1abe55efSEd Tanous class Chassis : public Node 173*1abe55efSEd Tanous { 174e37f8451SRapkiewicz, Pawel public: 175*1abe55efSEd Tanous Chassis(CrowApp &app) : 176*1abe55efSEd Tanous Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 177*1abe55efSEd Tanous { 178e37f8451SRapkiewicz, Pawel Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 179e37f8451SRapkiewicz, Pawel Node::json["@odata.id"] = "/redfish/v1/Chassis"; 180e37f8451SRapkiewicz, Pawel Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis"; 181e37f8451SRapkiewicz, Pawel Node::json["Name"] = "Chassis Collection"; 1826c233015SEd Tanous Node::json["ChassisType"] = "RackMount"; 183e37f8451SRapkiewicz, Pawel 184e0d918bcSEd Tanous entityPrivileges = { 185e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 186e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 187e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 188e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 189e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 190e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 191e37f8451SRapkiewicz, Pawel } 192e37f8451SRapkiewicz, Pawel 193e37f8451SRapkiewicz, Pawel private: 194e37f8451SRapkiewicz, Pawel /** 195e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 196e37f8451SRapkiewicz, Pawel */ 19755c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 198*1abe55efSEd Tanous const std::vector<std::string> ¶ms) override 199*1abe55efSEd Tanous { 200e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 201e37f8451SRapkiewicz, Pawel // impossible. 202*1abe55efSEd Tanous if (params.size() != 1) 203*1abe55efSEd Tanous { 204e0d918bcSEd Tanous res.result(boost::beast::http::status::internal_server_error); 205e37f8451SRapkiewicz, Pawel res.end(); 206e37f8451SRapkiewicz, Pawel return; 207e37f8451SRapkiewicz, Pawel } 208e37f8451SRapkiewicz, Pawel 20955c7b7a2SEd Tanous res.jsonValue = Node::json; 21055c7b7a2SEd Tanous const std::string &chassisId = params[0]; 21155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 21255c7b7a2SEd Tanous [&res, chassisId(std::string(chassisId))]( 213daf36e2eSEd Tanous const boost::system::error_code error_code, 214daf36e2eSEd Tanous const std::vector<std::pair< 215*1abe55efSEd Tanous std::string, std::vector<std::pair< 216*1abe55efSEd Tanous std::string, std::vector<std::string>>>>> 217daf36e2eSEd Tanous &subtree) { 218*1abe55efSEd Tanous if (error_code) 219*1abe55efSEd Tanous { 22055c7b7a2SEd Tanous res.jsonValue = {}; 221*1abe55efSEd Tanous res.result( 222*1abe55efSEd Tanous boost::beast::http::status::internal_server_error); 223e37f8451SRapkiewicz, Pawel res.end(); 224daf36e2eSEd Tanous return; 225daf36e2eSEd Tanous } 226daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 227*1abe55efSEd Tanous for (const std::pair< 228*1abe55efSEd Tanous std::string, 229*1abe55efSEd Tanous std::vector< 230*1abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 231*1abe55efSEd Tanous &object : subtree) 232*1abe55efSEd Tanous { 233daf36e2eSEd Tanous const std::string &path = object.first; 234*1abe55efSEd Tanous const std::vector< 235*1abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 236daf36e2eSEd Tanous &connectionNames = object.second; 237e0d918bcSEd Tanous 238*1abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 239*1abe55efSEd Tanous { 240daf36e2eSEd Tanous continue; 241daf36e2eSEd Tanous } 242*1abe55efSEd Tanous if (connectionNames.size() < 1) 243*1abe55efSEd Tanous { 244*1abe55efSEd Tanous BMCWEB_LOG_ERROR << "Only got " 245*1abe55efSEd Tanous << connectionNames.size() 24655c7b7a2SEd Tanous << " Connection names"; 247e0d918bcSEd Tanous continue; 248daf36e2eSEd Tanous } 249e0d918bcSEd Tanous 250daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 25155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 25255c7b7a2SEd Tanous [&res, chassisId(std::string(chassisId))]( 253daf36e2eSEd Tanous const boost::system::error_code error_code, 254*1abe55efSEd Tanous const std::vector<std::pair< 255*1abe55efSEd Tanous std::string, VariantType>> &propertiesList) { 256*1abe55efSEd Tanous for (const std::pair<std::string, VariantType> 257*1abe55efSEd Tanous &property : propertiesList) 258*1abe55efSEd Tanous { 259daf36e2eSEd Tanous const std::string *value = 260*1abe55efSEd Tanous mapbox::getPtr<const std::string>( 261*1abe55efSEd Tanous property.second); 262*1abe55efSEd Tanous if (value != nullptr) 263*1abe55efSEd Tanous { 26455c7b7a2SEd Tanous res.jsonValue[property.first] = *value; 265daf36e2eSEd Tanous } 266daf36e2eSEd Tanous } 26755c7b7a2SEd Tanous res.jsonValue["Name"] = chassisId; 26855c7b7a2SEd Tanous res.jsonValue["Id"] = chassisId; 26955c7b7a2SEd Tanous res.jsonValue["Thermal"] = { 270*1abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 271*1abe55efSEd Tanous chassisId + "/Thermal"}}; 272daf36e2eSEd Tanous res.end(); 273daf36e2eSEd Tanous }, 274daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 275*1abe55efSEd Tanous "GetAll", 276*1abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 27755c7b7a2SEd Tanous // Found the Connection we were looking for, return 278daf36e2eSEd Tanous return; 279daf36e2eSEd Tanous } 280e0d918bcSEd Tanous 281daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 282e0d918bcSEd Tanous res.result(boost::beast::http::status::not_found); 283e0d918bcSEd Tanous 284daf36e2eSEd Tanous res.end(); 285daf36e2eSEd Tanous }, 286daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 287daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 288daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 289daf36e2eSEd Tanous "/xyz/openbmc_project/inventory", int32_t(0), 290daf36e2eSEd Tanous std::array<const char *, 1>{ 291daf36e2eSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"}); 292e37f8451SRapkiewicz, Pawel } 293e37f8451SRapkiewicz, Pawel 294e37f8451SRapkiewicz, Pawel // Chassis Provider object 295e37f8451SRapkiewicz, Pawel // TODO(Pawel) consider move it to singleton 29655c7b7a2SEd Tanous OnDemandChassisProvider chassisProvider; 297e0d918bcSEd Tanous }; // namespace redfish 298e37f8451SRapkiewicz, Pawel 299e37f8451SRapkiewicz, Pawel } // namespace redfish 300