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 41c181942fSQiang XU void getIntrusionByService(std::shared_ptr<AsyncResp> aResp, 42c181942fSQiang XU const std::string &service, 43c181942fSQiang XU const std::string &objPath) 44c181942fSQiang XU { 45c181942fSQiang XU BMCWEB_LOG_DEBUG << "Get intrusion status by service \n"; 46c181942fSQiang XU 47c181942fSQiang XU crow::connections::systemBus->async_method_call( 48c181942fSQiang XU [aResp{std::move(aResp)}](const boost::system::error_code ec, 49c181942fSQiang XU const std::variant<std::string> &value) { 50c181942fSQiang XU if (ec) 51c181942fSQiang XU { 52c181942fSQiang XU // do not add err msg in redfish response, becaues this is not 53c181942fSQiang XU // mandatory property 54c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n"; 55c181942fSQiang XU return; 56c181942fSQiang XU } 57c181942fSQiang XU 58c181942fSQiang XU const std::string *status = std::get_if<std::string>(&value); 59c181942fSQiang XU 60c181942fSQiang XU if (status == nullptr) 61c181942fSQiang XU { 62c181942fSQiang XU BMCWEB_LOG_ERROR << "intrusion status read error \n"; 63c181942fSQiang XU return; 64c181942fSQiang XU } 65c181942fSQiang XU 66c181942fSQiang XU aResp->res.jsonValue["PhysicalSecurity"] = { 67c181942fSQiang XU {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}}; 68c181942fSQiang XU }, 69c181942fSQiang XU service, objPath, "org.freedesktop.DBus.Properties", "Get", 70c181942fSQiang XU "xyz.openbmc_project.Chassis.Intrusion", "Status"); 71c181942fSQiang XU } 72c181942fSQiang XU 73c181942fSQiang XU /** 74c181942fSQiang XU * Retrieves physical security properties over dbus 75c181942fSQiang XU */ 76c181942fSQiang XU void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp) 77c181942fSQiang XU { 78c181942fSQiang XU crow::connections::systemBus->async_method_call( 79c181942fSQiang XU [aResp{std::move(aResp)}]( 80c181942fSQiang XU const boost::system::error_code ec, 81c181942fSQiang XU const std::vector<std::pair< 82c181942fSQiang XU std::string, 83c181942fSQiang XU std::vector<std::pair<std::string, std::vector<std::string>>>>> 84c181942fSQiang XU &subtree) { 85c181942fSQiang XU if (ec) 86c181942fSQiang XU { 87c181942fSQiang XU // do not add err msg in redfish response, becaues this is not 88c181942fSQiang XU // mandatory property 89c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec 90c181942fSQiang XU << "\n"; 91c181942fSQiang XU return; 92c181942fSQiang XU } 93c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 94c181942fSQiang XU for (const auto &object : subtree) 95c181942fSQiang XU { 96c181942fSQiang XU for (const auto &service : object.second) 97c181942fSQiang XU { 98c181942fSQiang XU getIntrusionByService(aResp, service.first, object.first); 99c181942fSQiang XU return; 100c181942fSQiang XU } 101c181942fSQiang XU } 102c181942fSQiang XU }, 103c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", 104c181942fSQiang XU "/xyz/openbmc_project/object_mapper", 105c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", "GetSubTree", 106c181942fSQiang XU "/xyz/openbmc_project/Intrusion", int32_t(1), 107c181942fSQiang XU std::array<const char *, 1>{"xyz.openbmc_project.Chassis.Intrusion"}); 108c181942fSQiang XU } 109c181942fSQiang 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 { 1340f74e643SEd Tanous res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection"; 1350f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 1360f74e643SEd Tanous res.jsonValue["@odata.context"] = 1370f74e643SEd Tanous "/redfish/v1/$metadata#ChassisCollection.ChassisCollection"; 1380f74e643SEd Tanous res.jsonValue["Name"] = "Chassis Collection"; 1390f74e643SEd Tanous 140*603a6640SGunnar Mills #ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS 141*603a6640SGunnar Mills // Assume one Chassis named "chassis" 142*603a6640SGunnar Mills res.jsonValue["Members@odata.count"] = 1; 143*603a6640SGunnar Mills res.jsonValue["Members"] = { 144*603a6640SGunnar Mills {{"@odata.id", "/redfish/v1/Chassis/chassis"}}}; 145*603a6640SGunnar Mills res.end(); 146*603a6640SGunnar Mills return; 147*603a6640SGunnar Mills #endif 148*603a6640SGunnar Mills const std::array<const char *, 3> interfaces = { 149*603a6640SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 150*603a6640SGunnar Mills "xyz.openbmc_project.Inventory.Item.Chassis", 151*603a6640SGunnar Mills "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 152*603a6640SGunnar Mills 15362d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 15462d5e2e4SEd Tanous crow::connections::systemBus->async_method_call( 15562d5e2e4SEd Tanous [asyncResp](const boost::system::error_code ec, 15662d5e2e4SEd Tanous const std::vector<std::string> &chassisList) { 15762d5e2e4SEd Tanous if (ec) 1581abe55efSEd Tanous { 159f12894f8SJason M. Bills messages::internalError(asyncResp->res); 16062d5e2e4SEd Tanous return; 161e37f8451SRapkiewicz, Pawel } 16262d5e2e4SEd Tanous nlohmann::json &chassisArray = 16362d5e2e4SEd Tanous asyncResp->res.jsonValue["Members"]; 16462d5e2e4SEd Tanous chassisArray = nlohmann::json::array(); 16562d5e2e4SEd Tanous for (const std::string &objpath : chassisList) 16662d5e2e4SEd Tanous { 16762d5e2e4SEd Tanous std::size_t lastPos = objpath.rfind("/"); 16862d5e2e4SEd Tanous if (lastPos == std::string::npos) 16962d5e2e4SEd Tanous { 17062d5e2e4SEd Tanous BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 17162d5e2e4SEd Tanous continue; 17262d5e2e4SEd Tanous } 17362d5e2e4SEd Tanous chassisArray.push_back( 17462d5e2e4SEd Tanous {{"@odata.id", "/redfish/v1/Chassis/" + 17562d5e2e4SEd Tanous objpath.substr(lastPos + 1)}}); 176e37f8451SRapkiewicz, Pawel } 177e37f8451SRapkiewicz, Pawel 17862d5e2e4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 17962d5e2e4SEd Tanous chassisArray.size(); 18062d5e2e4SEd Tanous }, 18162d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", 18262d5e2e4SEd Tanous "/xyz/openbmc_project/object_mapper", 18362d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 184734bfe90SGunnar Mills "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 18562d5e2e4SEd Tanous } 186e37f8451SRapkiewicz, Pawel }; 187e37f8451SRapkiewicz, Pawel 188e37f8451SRapkiewicz, Pawel /** 189e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 190e37f8451SRapkiewicz, Pawel */ 1911abe55efSEd Tanous class Chassis : public Node 1921abe55efSEd Tanous { 193e37f8451SRapkiewicz, Pawel public: 1941abe55efSEd Tanous Chassis(CrowApp &app) : 1951abe55efSEd Tanous Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 1961abe55efSEd Tanous { 197e0d918bcSEd Tanous entityPrivileges = { 198e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 199e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 200e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 201e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 202e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 203e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 204e37f8451SRapkiewicz, Pawel } 205e37f8451SRapkiewicz, Pawel 206e37f8451SRapkiewicz, Pawel private: 207e37f8451SRapkiewicz, Pawel /** 208e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 209e37f8451SRapkiewicz, Pawel */ 21055c7b7a2SEd Tanous void doGet(crow::Response &res, const crow::Request &req, 2111abe55efSEd Tanous const std::vector<std::string> ¶ms) override 2121abe55efSEd Tanous { 213734bfe90SGunnar Mills const std::array<const char *, 3> interfaces = { 214734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 215734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Chassis", 216734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 217734bfe90SGunnar Mills 218e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 219e37f8451SRapkiewicz, Pawel // impossible. 2201abe55efSEd Tanous if (params.size() != 1) 2211abe55efSEd Tanous { 222f12894f8SJason M. Bills messages::internalError(res); 223e37f8451SRapkiewicz, Pawel res.end(); 224e37f8451SRapkiewicz, Pawel return; 225e37f8451SRapkiewicz, Pawel } 22699cffd7fSShawn McCarney const std::string &chassisId = params[0]; 227*603a6640SGunnar Mills #ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS 228*603a6640SGunnar Mills // In a one chassis system the only supported name is "chassis" 229*603a6640SGunnar Mills if (chassisId != "chassis") 230*603a6640SGunnar Mills { 231*603a6640SGunnar Mills messages::resourceNotFound(res, "#Chassis.v1_4_0.Chassis", 232*603a6640SGunnar Mills chassisId); 233*603a6640SGunnar Mills res.end(); 234*603a6640SGunnar Mills return; 235*603a6640SGunnar Mills } 236*603a6640SGunnar Mills #endif 237e37f8451SRapkiewicz, Pawel 2380f74e643SEd Tanous res.jsonValue["@odata.type"] = "#Chassis.v1_4_0.Chassis"; 23999cffd7fSShawn McCarney res.jsonValue["@odata.id"] = "/redfish/v1/Chassis/" + chassisId; 2400f74e643SEd Tanous res.jsonValue["@odata.context"] = 2410f74e643SEd Tanous "/redfish/v1/$metadata#Chassis.Chassis"; 2420f74e643SEd Tanous res.jsonValue["Name"] = "Chassis Collection"; 2430f74e643SEd Tanous res.jsonValue["ChassisType"] = "RackMount"; 2440f74e643SEd Tanous res.jsonValue["PowerState"] = "On"; 2450f74e643SEd Tanous 24662d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 24755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 24862d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 24962d5e2e4SEd Tanous const boost::system::error_code ec, 250daf36e2eSEd Tanous const std::vector<std::pair< 2511abe55efSEd Tanous std::string, std::vector<std::pair< 2521abe55efSEd Tanous std::string, std::vector<std::string>>>>> 253daf36e2eSEd Tanous &subtree) { 25462d5e2e4SEd Tanous if (ec) 2551abe55efSEd Tanous { 256f12894f8SJason M. Bills messages::internalError(asyncResp->res); 257daf36e2eSEd Tanous return; 258daf36e2eSEd Tanous } 259daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 2601abe55efSEd Tanous for (const std::pair< 2611abe55efSEd Tanous std::string, 2621abe55efSEd Tanous std::vector< 2631abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>>> 2641abe55efSEd Tanous &object : subtree) 2651abe55efSEd Tanous { 266daf36e2eSEd Tanous const std::string &path = object.first; 2671abe55efSEd Tanous const std::vector< 2681abe55efSEd Tanous std::pair<std::string, std::vector<std::string>>> 269daf36e2eSEd Tanous &connectionNames = object.second; 270e0d918bcSEd Tanous 271*603a6640SGunnar Mills // If only one chassis, just select the first one 272*603a6640SGunnar Mills #ifndef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS 2731abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 2741abe55efSEd Tanous { 275daf36e2eSEd Tanous continue; 276daf36e2eSEd Tanous } 277*603a6640SGunnar Mills #endif 2781abe55efSEd Tanous if (connectionNames.size() < 1) 2791abe55efSEd Tanous { 2801abe55efSEd Tanous BMCWEB_LOG_ERROR << "Only got " 2811abe55efSEd Tanous << connectionNames.size() 28255c7b7a2SEd Tanous << " Connection names"; 283e0d918bcSEd Tanous continue; 284daf36e2eSEd Tanous } 285e0d918bcSEd Tanous 286daf36e2eSEd Tanous const std::string connectionName = connectionNames[0].first; 28755c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 28862d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 28962d5e2e4SEd Tanous const boost::system::error_code ec, 2901abe55efSEd Tanous const std::vector<std::pair< 2911abe55efSEd Tanous std::string, VariantType>> &propertiesList) { 2921abe55efSEd Tanous for (const std::pair<std::string, VariantType> 2931abe55efSEd Tanous &property : propertiesList) 2941abe55efSEd Tanous { 29599cffd7fSShawn McCarney // Store DBus properties that are also Redfish 29699cffd7fSShawn McCarney // properties with same name and a string value 29799cffd7fSShawn McCarney const std::string &propertyName = 29899cffd7fSShawn McCarney property.first; 29999cffd7fSShawn McCarney if ((propertyName == "PartNumber") || 30099cffd7fSShawn McCarney (propertyName == "SerialNumber") || 30199cffd7fSShawn McCarney (propertyName == "Manufacturer") || 30299cffd7fSShawn McCarney (propertyName == "Model")) 30399cffd7fSShawn McCarney { 304daf36e2eSEd Tanous const std::string *value = 30599cffd7fSShawn McCarney std::get_if<std::string>( 30699cffd7fSShawn McCarney &property.second); 3071abe55efSEd Tanous if (value != nullptr) 3081abe55efSEd Tanous { 30999cffd7fSShawn McCarney asyncResp->res.jsonValue[propertyName] = 31062d5e2e4SEd Tanous *value; 311daf36e2eSEd Tanous } 312daf36e2eSEd Tanous } 31399cffd7fSShawn McCarney } 31462d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 31562d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 31662d5e2e4SEd Tanous asyncResp->res.jsonValue["Thermal"] = { 3171abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3181abe55efSEd Tanous chassisId + "/Thermal"}}; 3192474adfaSEd Tanous // Power object 3202474adfaSEd Tanous asyncResp->res.jsonValue["Power"] = { 3212474adfaSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3222474adfaSEd Tanous chassisId + "/Power"}}; 323029573d4SEd Tanous asyncResp->res.jsonValue["Status"] = { 324029573d4SEd Tanous {"Health", "OK"}, 325029573d4SEd Tanous {"State", "Enabled"}, 326029573d4SEd Tanous }; 3272474adfaSEd Tanous 328029573d4SEd Tanous asyncResp->res 329029573d4SEd Tanous .jsonValue["Links"]["ComputerSystems"] = { 330029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Systems/system"}}}; 331029573d4SEd Tanous asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 332029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 333daf36e2eSEd Tanous }, 334daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 3351abe55efSEd Tanous "GetAll", 3361abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 337daf36e2eSEd Tanous return; 338daf36e2eSEd Tanous } 339e0d918bcSEd Tanous 340daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 341f12894f8SJason M. Bills messages::resourceNotFound( 342f12894f8SJason M. Bills asyncResp->res, "#Chassis.v1_4_0.Chassis", chassisId); 343daf36e2eSEd Tanous }, 344daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 345daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 346daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 347734bfe90SGunnar Mills "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 348c181942fSQiang XU 349c181942fSQiang XU getPhysicalSecurityData(asyncResp); 350e37f8451SRapkiewicz, Pawel } 35162d5e2e4SEd Tanous }; 352e37f8451SRapkiewicz, Pawel } // namespace redfish 353