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" 191abe55efSEd Tanous 20e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp> 21abf2add6SEd Tanous #include <variant> 22e37f8451SRapkiewicz, Pawel 231abe55efSEd Tanous namespace redfish 241abe55efSEd Tanous { 25e37f8451SRapkiewicz, Pawel 26e37f8451SRapkiewicz, Pawel /** 27e37f8451SRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 28e37f8451SRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 29e37f8451SRapkiewicz, Pawel */ 3055c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get 31aa2e59c1SEd Tanous // values, it should be as simple as possible 32aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type 33abf2add6SEd Tanous using VariantType = std::variant<bool, std::string, uint64_t>; 34aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair< 35aa2e59c1SEd Tanous sdbusplus::message::object_path, 36aa2e59c1SEd Tanous std::vector<std::pair<std::string, 37aa2e59c1SEd Tanous std::vector<std::pair<std::string, VariantType>>>>>>; 38e37f8451SRapkiewicz, Pawel 39aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>; 40e37f8451SRapkiewicz, Pawel 41*c181942fSQiang XU void getIntrusionByService(std::shared_ptr<AsyncResp> aResp, 42*c181942fSQiang XU const std::string &service, 43*c181942fSQiang XU const std::string &objPath) 44*c181942fSQiang XU { 45*c181942fSQiang XU BMCWEB_LOG_DEBUG << "Get intrusion status by service \n"; 46*c181942fSQiang XU 47*c181942fSQiang XU crow::connections::systemBus->async_method_call( 48*c181942fSQiang XU [aResp{std::move(aResp)}](const boost::system::error_code ec, 49*c181942fSQiang XU const std::variant<std::string> &value) { 50*c181942fSQiang XU if (ec) 51*c181942fSQiang XU { 52*c181942fSQiang XU // do not add err msg in redfish response, becaues this is not 53*c181942fSQiang XU // mandatory property 54*c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n"; 55*c181942fSQiang XU return; 56*c181942fSQiang XU } 57*c181942fSQiang XU 58*c181942fSQiang XU const std::string *status = std::get_if<std::string>(&value); 59*c181942fSQiang XU 60*c181942fSQiang XU if (status == nullptr) 61*c181942fSQiang XU { 62*c181942fSQiang XU BMCWEB_LOG_ERROR << "intrusion status read error \n"; 63*c181942fSQiang XU return; 64*c181942fSQiang XU } 65*c181942fSQiang XU 66*c181942fSQiang XU aResp->res.jsonValue["PhysicalSecurity"] = { 67*c181942fSQiang XU {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}}; 68*c181942fSQiang XU }, 69*c181942fSQiang XU service, objPath, "org.freedesktop.DBus.Properties", "Get", 70*c181942fSQiang XU "xyz.openbmc_project.Chassis.Intrusion", "Status"); 71*c181942fSQiang XU } 72*c181942fSQiang XU 73*c181942fSQiang XU /** 74*c181942fSQiang XU * Retrieves physical security properties over dbus 75*c181942fSQiang XU */ 76*c181942fSQiang XU void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp) 77*c181942fSQiang XU { 78*c181942fSQiang XU crow::connections::systemBus->async_method_call( 79*c181942fSQiang XU [aResp{std::move(aResp)}]( 80*c181942fSQiang XU const boost::system::error_code ec, 81*c181942fSQiang XU const std::vector<std::pair< 82*c181942fSQiang XU std::string, 83*c181942fSQiang XU std::vector<std::pair<std::string, std::vector<std::string>>>>> 84*c181942fSQiang XU &subtree) { 85*c181942fSQiang XU if (ec) 86*c181942fSQiang XU { 87*c181942fSQiang XU // do not add err msg in redfish response, becaues this is not 88*c181942fSQiang XU // mandatory property 89*c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec 90*c181942fSQiang XU << "\n"; 91*c181942fSQiang XU return; 92*c181942fSQiang XU } 93*c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 94*c181942fSQiang XU for (const auto &object : subtree) 95*c181942fSQiang XU { 96*c181942fSQiang XU for (const auto &service : object.second) 97*c181942fSQiang XU { 98*c181942fSQiang XU getIntrusionByService(aResp, service.first, object.first); 99*c181942fSQiang XU return; 100*c181942fSQiang XU } 101*c181942fSQiang XU } 102*c181942fSQiang XU }, 103*c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", 104*c181942fSQiang XU "/xyz/openbmc_project/object_mapper", 105*c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", "GetSubTree", 106*c181942fSQiang XU "/xyz/openbmc_project/Intrusion", int32_t(1), 107*c181942fSQiang XU std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"}); 108*c181942fSQiang XU } 109*c181942fSQiang XU 110e37f8451SRapkiewicz, Pawel /** 111e37f8451SRapkiewicz, Pawel * ChassisCollection derived class for delivering Chassis Collection Schema 112e37f8451SRapkiewicz, Pawel */ 1131abe55efSEd Tanous class ChassisCollection : public Node 1141abe55efSEd Tanous { 115e37f8451SRapkiewicz, Pawel public: 1161abe55efSEd Tanous ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") 1171abe55efSEd Tanous { 118e0d918bcSEd Tanous entityPrivileges = { 119e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 120e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 121e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 122e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 123e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 124e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 125e37f8451SRapkiewicz, Pawel } 126e37f8451SRapkiewicz, Pawel 127e37f8451SRapkiewicz, Pawel private: 128e37f8451SRapkiewicz, Pawel /** 129e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 130e37f8451SRapkiewicz, Pawel */ 13155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 1321abe55efSEd Tanous const std::vector<std::string> ¶ms) override 1331abe55efSEd Tanous { 1348f1ac8e9SGunnar Mills const std::array<const char *, 3> interfaces = { 13562d5e2e4SEd Tanous "xyz.openbmc_project.Inventory.Item.Board", 13662d5e2e4SEd Tanous "xyz.openbmc_project.Inventory.Item.Chassis", 1378f1ac8e9SGunnar Mills "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 1380f74e643SEd Tanous res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection"; 1390f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 1400f74e643SEd Tanous res.jsonValue["@odata.context"] = 1410f74e643SEd Tanous "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 1420f74e643SEd Tanous res.jsonValue["Name"] = "Chassis Collection"; 1430f74e643SEd Tanous 14462d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 14562d5e2e4SEd Tanous crow::connections::systemBus->async_method_call( 14662d5e2e4SEd Tanous [asyncResp](const boost::system::error_code ec, 14762d5e2e4SEd Tanous const std::vector<std::string> &chassisList) { 14862d5e2e4SEd Tanous if (ec) 1491abe55efSEd Tanous { 150f12894f8SJason M. Bills messages::internalError(asyncResp->res); 15162d5e2e4SEd Tanous return; 152e37f8451SRapkiewicz, Pawel } 15362d5e2e4SEd Tanous nlohmann::json &chassisArray = 15462d5e2e4SEd Tanous asyncResp->res.jsonValue["Members"]; 15562d5e2e4SEd Tanous chassisArray = nlohmann::json::array(); 15662d5e2e4SEd Tanous for (const std::string &objpath : chassisList) 15762d5e2e4SEd Tanous { 15862d5e2e4SEd Tanous std::size_t lastPos = objpath.rfind("/"); 15962d5e2e4SEd Tanous if (lastPos == std::string::npos) 16062d5e2e4SEd Tanous { 16162d5e2e4SEd Tanous BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 16262d5e2e4SEd Tanous continue; 16362d5e2e4SEd Tanous } 16462d5e2e4SEd Tanous chassisArray.push_back( 16562d5e2e4SEd Tanous {{"@odata.id", "/redfish/v1/Chassis/" + 16662d5e2e4SEd Tanous objpath.substr(lastPos + 1)}}); 167e37f8451SRapkiewicz, Pawel } 168e37f8451SRapkiewicz, Pawel 16962d5e2e4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 17062d5e2e4SEd Tanous chassisArray.size(); 17162d5e2e4SEd Tanous }, 17262d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", 17362d5e2e4SEd Tanous "/xyz/openbmc_project/object_mapper", 17462d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 175734bfe90SGunnar Mills "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 17662d5e2e4SEd Tanous } 177e37f8451SRapkiewicz, Pawel }; 178e37f8451SRapkiewicz, Pawel 179e37f8451SRapkiewicz, Pawel /** 180e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 181e37f8451SRapkiewicz, Pawel */ 1821abe55efSEd Tanous class Chassis : public Node 1831abe55efSEd Tanous { 184e37f8451SRapkiewicz, Pawel public: 1851abe55efSEd Tanous Chassis(CrowApp &app) : 1861abe55efSEd Tanous Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 1871abe55efSEd Tanous { 188e0d918bcSEd Tanous entityPrivileges = { 189e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 190e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 191e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 192e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 193e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 194e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 195e37f8451SRapkiewicz, Pawel } 196e37f8451SRapkiewicz, Pawel 197e37f8451SRapkiewicz, Pawel private: 198e37f8451SRapkiewicz, Pawel /** 199e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 200e37f8451SRapkiewicz, Pawel */ 20155c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 2021abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2031abe55efSEd Tanous { 204734bfe90SGunnar Mills const std::array<const char *, 3> interfaces = { 205734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 206734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Chassis", 207734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 208734bfe90SGunnar Mills 209e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 210e37f8451SRapkiewicz, Pawel // impossible. 2111abe55efSEd Tanous if (params.size() != 1) 2121abe55efSEd Tanous { 213f12894f8SJason M. Bills messages::internalError(res); 214e37f8451SRapkiewicz, Pawel res.end(); 215e37f8451SRapkiewicz, Pawel return; 216e37f8451SRapkiewicz, Pawel } 21799cffd7fSShawn McCarney const std::string &chassisId = params[0]; 218e37f8451SRapkiewicz, Pawel 2190f74e643SEd Tanous res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 22099cffd7fSShawn McCarney res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + chassisId; 2210f74e643SEd Tanous res.jsonValue["@odata.context"] = 2220f74e643SEd Tanous "/redfish/v1/$metadata#Chassis.Chassis"; 2230f74e643SEd Tanous res.jsonValue["Name"] = "Chassis Collection"; 2240f74e643SEd Tanous res.jsonValue["ChassisType"] = "RackMount"; 2250f74e643SEd Tanous res.jsonValue["PowerState"] = "On"; 2260f74e643SEd Tanous 22762d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 22855c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 22962d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 23062d5e2e4SEd Tanous const boost::system::error_code ec, 231daf36e2eSEd Tanous const std::vector<std::pair< 2321abe55efSEd Tanous std::string, std::vector<std::pair< 2331abe55efSEd Tanous std::string, std::vector<std::string>>>>> 234daf36e2eSEd Tanous &subtree) { 23562d5e2e4SEd Tanous if (ec) 2361abe55efSEd Tanous { 237f12894f8SJason M. Bills messages::internalError(asyncResp->res); 238daf36e2eSEd Tanous return; 239daf36e2eSEd Tanous } 240daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 2411abe55efSEd Tanous for (const std::pair< 2421abe55efSEd Tanous std::string, 2431abe55efSEd Tanous std::vector< 2441abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 2451abe55efSEd Tanous &object : subtree) 2461abe55efSEd Tanous { 247daf36e2eSEd Tanous const std::string &path = object.first; 2481abe55efSEd Tanous const std::vector< 2491abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 250daf36e2eSEd Tanous &connectionNames = object.second; 251e0d918bcSEd Tanous 2521abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 2531abe55efSEd Tanous { 254daf36e2eSEd Tanous continue; 255daf36e2eSEd Tanous } 2561abe55efSEd Tanous if (connectionNames.size() < 1) 2571abe55efSEd Tanous { 2581abe55efSEd Tanous BMCWEB_LOG_ERROR << "Only got " 2591abe55efSEd Tanous << connectionNames.size() 26055c7b7a2SEd Tanous << " Connection names"; 261e0d918bcSEd Tanous continue; 262daf36e2eSEd Tanous } 263e0d918bcSEd Tanous 264daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 26555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 26662d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 26762d5e2e4SEd Tanous const boost::system::error_code ec, 2681abe55efSEd Tanous const std::vector<std::pair< 2691abe55efSEd Tanous std::string, VariantType>> &propertiesList) { 2701abe55efSEd Tanous for (const std::pair<std::string, VariantType> 2711abe55efSEd Tanous &property : propertiesList) 2721abe55efSEd Tanous { 27399cffd7fSShawn McCarney // Store DBus properties that are also Redfish 27499cffd7fSShawn McCarney // properties with same name and a string value 27599cffd7fSShawn McCarney const std::string &propertyName = 27699cffd7fSShawn McCarney property.first; 27799cffd7fSShawn McCarney if ((propertyName == "PartNumber") || 27899cffd7fSShawn McCarney (propertyName == "SerialNumber") || 27999cffd7fSShawn McCarney (propertyName == "Manufacturer") || 28099cffd7fSShawn McCarney (propertyName == "Model")) 28199cffd7fSShawn McCarney { 282daf36e2eSEd Tanous const std::string *value = 28399cffd7fSShawn McCarney std::get_if<std::string>( 28499cffd7fSShawn McCarney &property.second); 2851abe55efSEd Tanous if (value != nullptr) 2861abe55efSEd Tanous { 28799cffd7fSShawn McCarney asyncResp->res.jsonValue[propertyName] = 28862d5e2e4SEd Tanous *value; 289daf36e2eSEd Tanous } 290daf36e2eSEd Tanous } 29199cffd7fSShawn McCarney } 29262d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 29362d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 29462d5e2e4SEd Tanous asyncResp->res.jsonValue["Thermal"] = { 2951abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 2961abe55efSEd Tanous chassisId + "/Thermal"}}; 2972474adfaSEd Tanous // Power object 2982474adfaSEd Tanous asyncResp->res.jsonValue["Power"] = { 2992474adfaSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3002474adfaSEd Tanous chassisId + "/Power"}}; 301029573d4SEd Tanous asyncResp->res.jsonValue["Status"] = { 302029573d4SEd Tanous {"Health", "OK"}, 303029573d4SEd Tanous {"State", "Enabled"}, 304029573d4SEd Tanous }; 3052474adfaSEd Tanous 306029573d4SEd Tanous asyncResp->res 307029573d4SEd Tanous .jsonValue["Links"]["ComputerSystems"] = { 308029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Systems/system"}}}; 309029573d4SEd Tanous asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 310029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 311daf36e2eSEd Tanous }, 312daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 3131abe55efSEd Tanous "GetAll", 3141abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 315daf36e2eSEd Tanous return; 316daf36e2eSEd Tanous } 317e0d918bcSEd Tanous 318daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 319f12894f8SJason M. Bills messages::resourceNotFound( 320f12894f8SJason M. Bills asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId); 321daf36e2eSEd Tanous }, 322daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 323daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 324daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 325734bfe90SGunnar Mills "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 326*c181942fSQiang XU 327*c181942fSQiang XU getPhysicalSecurityData(asyncResp); 328e37f8451SRapkiewicz, Pawel } 32962d5e2e4SEd Tanous }; 330e37f8451SRapkiewicz, Pawel } // namespace redfish 331