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 18b49ac873SJames Feist #include "health.hpp" 191c8fba97SJames Feist #include "led.hpp" 20e37f8451SRapkiewicz, Pawel #include "node.hpp" 211abe55efSEd Tanous 22e37f8451SRapkiewicz, Pawel #include <boost/container/flat_map.hpp> 231214b7e7SGunnar Mills 24abf2add6SEd Tanous #include <variant> 25e37f8451SRapkiewicz, Pawel 261abe55efSEd Tanous namespace redfish 271abe55efSEd Tanous { 28e37f8451SRapkiewicz, Pawel 29e37f8451SRapkiewicz, Pawel /** 30beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 31beeca0aeSGunnar Mills * 32beeca0aeSGunnar Mills * @param[in] aResp - Shared pointer for completing asynchronous calls. 33beeca0aeSGunnar Mills * 34beeca0aeSGunnar Mills * @return None. 35beeca0aeSGunnar Mills */ 36beeca0aeSGunnar Mills void getChassisState(std::shared_ptr<AsyncResp> aResp) 37beeca0aeSGunnar Mills { 38beeca0aeSGunnar Mills crow::connections::systemBus->async_method_call( 39beeca0aeSGunnar Mills [aResp{std::move(aResp)}]( 40beeca0aeSGunnar Mills const boost::system::error_code ec, 41beeca0aeSGunnar Mills const std::variant<std::string>& chassisState) { 42beeca0aeSGunnar Mills if (ec) 43beeca0aeSGunnar Mills { 44beeca0aeSGunnar Mills BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 45beeca0aeSGunnar Mills messages::internalError(aResp->res); 46beeca0aeSGunnar Mills return; 47beeca0aeSGunnar Mills } 48beeca0aeSGunnar Mills 49beeca0aeSGunnar Mills const std::string* s = std::get_if<std::string>(&chassisState); 50beeca0aeSGunnar Mills BMCWEB_LOG_DEBUG << "Chassis state: " << *s; 51beeca0aeSGunnar Mills if (s != nullptr) 52beeca0aeSGunnar Mills { 53beeca0aeSGunnar Mills // Verify Chassis State 54beeca0aeSGunnar Mills if (*s == "xyz.openbmc_project.State.Chassis.PowerState.On") 55beeca0aeSGunnar Mills { 56beeca0aeSGunnar Mills aResp->res.jsonValue["PowerState"] = "On"; 57beeca0aeSGunnar Mills aResp->res.jsonValue["Status"]["State"] = "Enabled"; 58beeca0aeSGunnar Mills } 59beeca0aeSGunnar Mills else if (*s == 60beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 61beeca0aeSGunnar Mills { 62beeca0aeSGunnar Mills aResp->res.jsonValue["PowerState"] = "Off"; 63beeca0aeSGunnar Mills aResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 64beeca0aeSGunnar Mills } 65beeca0aeSGunnar Mills } 66beeca0aeSGunnar Mills }, 67beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis", 68beeca0aeSGunnar Mills "/xyz/openbmc_project/state/chassis0", 69beeca0aeSGunnar Mills "org.freedesktop.DBus.Properties", "Get", 70beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis", "CurrentPowerState"); 71beeca0aeSGunnar Mills } 72beeca0aeSGunnar Mills 73beeca0aeSGunnar Mills /** 74e37f8451SRapkiewicz, Pawel * DBus types primitives for several generic DBus interfaces 75e37f8451SRapkiewicz, Pawel * TODO(Pawel) consider move this to separate file into boost::dbus 76e37f8451SRapkiewicz, Pawel */ 7755c7b7a2SEd Tanous // Note, this is not a very useful Variant, but because it isn't used to get 78aa2e59c1SEd Tanous // values, it should be as simple as possible 79aa2e59c1SEd Tanous // TODO(ed) invent a nullvariant type 805fd7ba65SCheng C Yang using VariantType = std::variant<bool, std::string, uint64_t, uint32_t>; 81aa2e59c1SEd Tanous using ManagedObjectsType = std::vector<std::pair< 82aa2e59c1SEd Tanous sdbusplus::message::object_path, 83aa2e59c1SEd Tanous std::vector<std::pair<std::string, 84aa2e59c1SEd Tanous std::vector<std::pair<std::string, VariantType>>>>>>; 85e37f8451SRapkiewicz, Pawel 86aa2e59c1SEd Tanous using PropertiesType = boost::container::flat_map<std::string, VariantType>; 87e37f8451SRapkiewicz, Pawel 88c181942fSQiang XU void getIntrusionByService(std::shared_ptr<AsyncResp> aResp, 89c181942fSQiang XU const std::string& service, 90c181942fSQiang XU const std::string& objPath) 91c181942fSQiang XU { 92c181942fSQiang XU BMCWEB_LOG_DEBUG << "Get intrusion status by service \n"; 93c181942fSQiang XU 94c181942fSQiang XU crow::connections::systemBus->async_method_call( 95c181942fSQiang XU [aResp{std::move(aResp)}](const boost::system::error_code ec, 96c181942fSQiang XU const std::variant<std::string>& value) { 97c181942fSQiang XU if (ec) 98c181942fSQiang XU { 994e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 100c181942fSQiang XU // mandatory property 101c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n"; 102c181942fSQiang XU return; 103c181942fSQiang XU } 104c181942fSQiang XU 105c181942fSQiang XU const std::string* status = std::get_if<std::string>(&value); 106c181942fSQiang XU 107c181942fSQiang XU if (status == nullptr) 108c181942fSQiang XU { 109c181942fSQiang XU BMCWEB_LOG_ERROR << "intrusion status read error \n"; 110c181942fSQiang XU return; 111c181942fSQiang XU } 112c181942fSQiang XU 113c181942fSQiang XU aResp->res.jsonValue["PhysicalSecurity"] = { 114c181942fSQiang XU {"IntrusionSensorNumber", 1}, {"IntrusionSensor", *status}}; 115c181942fSQiang XU }, 116c181942fSQiang XU service, objPath, "org.freedesktop.DBus.Properties", "Get", 117c181942fSQiang XU "xyz.openbmc_project.Chassis.Intrusion", "Status"); 118c181942fSQiang XU } 119c181942fSQiang XU 120c181942fSQiang XU /** 121c181942fSQiang XU * Retrieves physical security properties over dbus 122c181942fSQiang XU */ 123c181942fSQiang XU void getPhysicalSecurityData(std::shared_ptr<AsyncResp> aResp) 124c181942fSQiang XU { 125c181942fSQiang XU crow::connections::systemBus->async_method_call( 126c181942fSQiang XU [aResp{std::move(aResp)}]( 127c181942fSQiang XU const boost::system::error_code ec, 128c181942fSQiang XU const std::vector<std::pair< 129c181942fSQiang XU std::string, 1301214b7e7SGunnar Mills std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1311214b7e7SGunnar Mills subtree) { 132c181942fSQiang XU if (ec) 133c181942fSQiang XU { 1344e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 135c181942fSQiang XU // mandatory property 136c181942fSQiang XU BMCWEB_LOG_ERROR << "DBUS error: no matched iface " << ec 137c181942fSQiang XU << "\n"; 138c181942fSQiang XU return; 139c181942fSQiang XU } 140c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 141c181942fSQiang XU for (const auto& object : subtree) 142c181942fSQiang XU { 143c181942fSQiang XU for (const auto& service : object.second) 144c181942fSQiang XU { 145c181942fSQiang XU getIntrusionByService(aResp, service.first, object.first); 146c181942fSQiang XU return; 147c181942fSQiang XU } 148c181942fSQiang XU } 149c181942fSQiang XU }, 150c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", 151c181942fSQiang XU "/xyz/openbmc_project/object_mapper", 152c181942fSQiang XU "xyz.openbmc_project.ObjectMapper", "GetSubTree", 153271584abSEd Tanous "/xyz/openbmc_project/Intrusion", 1, 154c181942fSQiang XU std::array<const char*, 1>{"xyz.openbmc_project.Chassis.Intrusion"}); 155c181942fSQiang XU } 156c181942fSQiang XU 157e37f8451SRapkiewicz, Pawel /** 158e37f8451SRapkiewicz, Pawel * ChassisCollection derived class for delivering Chassis Collection Schema 159e37f8451SRapkiewicz, Pawel */ 1601abe55efSEd Tanous class ChassisCollection : public Node 1611abe55efSEd Tanous { 162e37f8451SRapkiewicz, Pawel public: 1631abe55efSEd Tanous ChassisCollection(CrowApp& app) : Node(app, "/redfish/v1/Chassis/") 1641abe55efSEd Tanous { 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, 1791abe55efSEd Tanous const std::vector<std::string>& params) override 1801abe55efSEd Tanous { 1810f74e643SEd Tanous res.jsonValue["@odata.type"] = "#ChassisCollection.ChassisCollection"; 1820f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 1830f74e643SEd Tanous res.jsonValue["Name"] = "Chassis Collection"; 1840f74e643SEd Tanous 185adc4f0dbSShawn McCarney const std::array<const char*, 2> interfaces = { 186603a6640SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 187adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 188603a6640SGunnar Mills 18962d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 19062d5e2e4SEd Tanous crow::connections::systemBus->async_method_call( 19162d5e2e4SEd Tanous [asyncResp](const boost::system::error_code ec, 19262d5e2e4SEd Tanous const std::vector<std::string>& chassisList) { 19362d5e2e4SEd Tanous if (ec) 1941abe55efSEd Tanous { 195f12894f8SJason M. Bills messages::internalError(asyncResp->res); 19662d5e2e4SEd Tanous return; 197e37f8451SRapkiewicz, Pawel } 19862d5e2e4SEd Tanous nlohmann::json& chassisArray = 19962d5e2e4SEd Tanous asyncResp->res.jsonValue["Members"]; 20062d5e2e4SEd Tanous chassisArray = nlohmann::json::array(); 20162d5e2e4SEd Tanous for (const std::string& objpath : chassisList) 20262d5e2e4SEd Tanous { 20362d5e2e4SEd Tanous std::size_t lastPos = objpath.rfind("/"); 20462d5e2e4SEd Tanous if (lastPos == std::string::npos) 20562d5e2e4SEd Tanous { 20662d5e2e4SEd Tanous BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath; 20762d5e2e4SEd Tanous continue; 20862d5e2e4SEd Tanous } 20962d5e2e4SEd Tanous chassisArray.push_back( 21062d5e2e4SEd Tanous {{"@odata.id", "/redfish/v1/Chassis/" + 21162d5e2e4SEd Tanous objpath.substr(lastPos + 1)}}); 212e37f8451SRapkiewicz, Pawel } 213e37f8451SRapkiewicz, Pawel 21462d5e2e4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 21562d5e2e4SEd Tanous chassisArray.size(); 21662d5e2e4SEd Tanous }, 21762d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", 21862d5e2e4SEd Tanous "/xyz/openbmc_project/object_mapper", 21962d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 220271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 22162d5e2e4SEd Tanous } 222e37f8451SRapkiewicz, Pawel }; 223e37f8451SRapkiewicz, Pawel 224e37f8451SRapkiewicz, Pawel /** 225e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 226e37f8451SRapkiewicz, Pawel */ 2271abe55efSEd Tanous class Chassis : public Node 2281abe55efSEd Tanous { 229e37f8451SRapkiewicz, Pawel public: 2301abe55efSEd Tanous Chassis(CrowApp& app) : 2311abe55efSEd Tanous Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 2321abe55efSEd Tanous { 233e0d918bcSEd Tanous entityPrivileges = { 234e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 235e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 236e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 237e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 238e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 239e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 240e37f8451SRapkiewicz, Pawel } 241e37f8451SRapkiewicz, Pawel 242e37f8451SRapkiewicz, Pawel private: 243e37f8451SRapkiewicz, Pawel /** 244e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 245e37f8451SRapkiewicz, Pawel */ 24655c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 2471abe55efSEd Tanous const std::vector<std::string>& params) override 2481abe55efSEd Tanous { 249adc4f0dbSShawn McCarney const std::array<const char*, 2> interfaces = { 250734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 251adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 252734bfe90SGunnar Mills 253e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 254e37f8451SRapkiewicz, Pawel // impossible. 2551abe55efSEd Tanous if (params.size() != 1) 2561abe55efSEd Tanous { 257f12894f8SJason M. Bills messages::internalError(res); 258e37f8451SRapkiewicz, Pawel res.end(); 259e37f8451SRapkiewicz, Pawel return; 260e37f8451SRapkiewicz, Pawel } 26199cffd7fSShawn McCarney const std::string& chassisId = params[0]; 262e37f8451SRapkiewicz, Pawel 26362d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 26455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 26562d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 26662d5e2e4SEd Tanous const boost::system::error_code ec, 2671c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 26862d5e2e4SEd Tanous if (ec) 2691abe55efSEd Tanous { 270f12894f8SJason M. Bills messages::internalError(asyncResp->res); 271daf36e2eSEd Tanous return; 272daf36e2eSEd Tanous } 273daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 2741abe55efSEd Tanous for (const std::pair< 2751abe55efSEd Tanous std::string, 2761abe55efSEd Tanous std::vector< 2771214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 2781214b7e7SGunnar Mills object : subtree) 2791abe55efSEd Tanous { 280daf36e2eSEd Tanous const std::string& path = object.first; 2811abe55efSEd Tanous const std::vector< 2821214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 2831214b7e7SGunnar Mills connectionNames = object.second; 284e0d918bcSEd Tanous 2851abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 2861abe55efSEd Tanous { 287daf36e2eSEd Tanous continue; 288daf36e2eSEd Tanous } 28926f03899SShawn McCarney 290b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 291b49ac873SJames Feist 292b49ac873SJames Feist crow::connections::systemBus->async_method_call( 293b49ac873SJames Feist [health](const boost::system::error_code ec, 294b49ac873SJames Feist std::variant<std::vector<std::string>>& resp) { 295b49ac873SJames Feist if (ec) 296b49ac873SJames Feist { 297b49ac873SJames Feist return; // no sensors = no failures 298b49ac873SJames Feist } 299b49ac873SJames Feist std::vector<std::string>* data = 300b49ac873SJames Feist std::get_if<std::vector<std::string>>(&resp); 301b49ac873SJames Feist if (data == nullptr) 302b49ac873SJames Feist { 303b49ac873SJames Feist return; 304b49ac873SJames Feist } 305b49ac873SJames Feist health->inventory = std::move(*data); 306b49ac873SJames Feist }, 307b49ac873SJames Feist "xyz.openbmc_project.ObjectMapper", 308b49ac873SJames Feist path + "/all_sensors", 309b49ac873SJames Feist "org.freedesktop.DBus.Properties", "Get", 310b49ac873SJames Feist "xyz.openbmc_project.Association", "endpoints"); 311b49ac873SJames Feist 312b49ac873SJames Feist health->populate(); 313b49ac873SJames Feist 3141abe55efSEd Tanous if (connectionNames.size() < 1) 3151abe55efSEd Tanous { 3161c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 317e0d918bcSEd Tanous continue; 318daf36e2eSEd Tanous } 319e0d918bcSEd Tanous 32049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.type"] = 321adbe192aSJason M. Bills "#Chassis.v1_10_0.Chassis"; 32249c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 32349c53ac9SJohnathan Mantey "/redfish/v1/Chassis/" + chassisId; 32449c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 32549c53ac9SJohnathan Mantey asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 326dd99e04bSP.K. Lee asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] = { 327dd99e04bSP.K. Lee {"target", "/redfish/v1/Chassis/" + chassisId + 328dd99e04bSP.K. Lee "/Actions/Chassis.Reset"}, 329*1cb1a9e6SAppaRao Puli {"@Redfish.ActionInfo", "/redfish/v1/Chassis/" + 330*1cb1a9e6SAppaRao Puli chassisId + 331*1cb1a9e6SAppaRao Puli "/ResetActionInfo"}}; 332adbe192aSJason M. Bills asyncResp->res.jsonValue["PCIeDevices"] = { 333adbe192aSJason M. Bills {"@odata.id", 334adbe192aSJason M. Bills "/redfish/v1/Systems/system/PCIeDevices"}}; 33549c53ac9SJohnathan Mantey 33649c53ac9SJohnathan Mantey const std::string& connectionName = 33749c53ac9SJohnathan Mantey connectionNames[0].first; 3381c8fba97SJames Feist 3391c8fba97SJames Feist const std::vector<std::string>& interfaces = 3401c8fba97SJames Feist connectionNames[0].second; 3411c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 3421c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 3431c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 3441c8fba97SJames Feist 3451c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 3461c8fba97SJames Feist { 3471c8fba97SJames Feist if (std::find(interfaces.begin(), interfaces.end(), 3481c8fba97SJames Feist interface) != interfaces.end()) 3491c8fba97SJames Feist { 3501c8fba97SJames Feist getIndicatorLedState(asyncResp); 3511c8fba97SJames Feist break; 3521c8fba97SJames Feist } 3531c8fba97SJames Feist } 3541c8fba97SJames Feist 35555c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 35662d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 35762d5e2e4SEd Tanous const boost::system::error_code ec, 3581abe55efSEd Tanous const std::vector<std::pair< 3591abe55efSEd Tanous std::string, VariantType>>& propertiesList) { 3601214b7e7SGunnar Mills for (const std::pair<std::string, VariantType>& 3611214b7e7SGunnar Mills property : propertiesList) 3621abe55efSEd Tanous { 36399cffd7fSShawn McCarney // Store DBus properties that are also Redfish 36499cffd7fSShawn McCarney // properties with same name and a string value 36599cffd7fSShawn McCarney const std::string& propertyName = 36699cffd7fSShawn McCarney property.first; 36799cffd7fSShawn McCarney if ((propertyName == "PartNumber") || 36899cffd7fSShawn McCarney (propertyName == "SerialNumber") || 36999cffd7fSShawn McCarney (propertyName == "Manufacturer") || 37099cffd7fSShawn McCarney (propertyName == "Model")) 37199cffd7fSShawn McCarney { 372daf36e2eSEd Tanous const std::string* value = 37399cffd7fSShawn McCarney std::get_if<std::string>( 37499cffd7fSShawn McCarney &property.second); 3751abe55efSEd Tanous if (value != nullptr) 3761abe55efSEd Tanous { 37799cffd7fSShawn McCarney asyncResp->res.jsonValue[propertyName] = 37862d5e2e4SEd Tanous *value; 379daf36e2eSEd Tanous } 380daf36e2eSEd Tanous } 38199cffd7fSShawn McCarney } 38262d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 38362d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 38462d5e2e4SEd Tanous asyncResp->res.jsonValue["Thermal"] = { 3851abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3861abe55efSEd Tanous chassisId + "/Thermal"}}; 3872474adfaSEd Tanous // Power object 3882474adfaSEd Tanous asyncResp->res.jsonValue["Power"] = { 3892474adfaSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3902474adfaSEd Tanous chassisId + "/Power"}}; 39195a3ecadSAnthony Wilson // SensorCollection 39295a3ecadSAnthony Wilson asyncResp->res.jsonValue["Sensors"] = { 39395a3ecadSAnthony Wilson {"@odata.id", "/redfish/v1/Chassis/" + 39495a3ecadSAnthony Wilson chassisId + "/Sensors"}}; 395029573d4SEd Tanous asyncResp->res.jsonValue["Status"] = { 396029573d4SEd Tanous {"State", "Enabled"}, 397029573d4SEd Tanous }; 3982474adfaSEd Tanous 399029573d4SEd Tanous asyncResp->res 400029573d4SEd Tanous .jsonValue["Links"]["ComputerSystems"] = { 401029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Systems/system"}}}; 402029573d4SEd Tanous asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 403029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 404beeca0aeSGunnar Mills getChassisState(asyncResp); 405daf36e2eSEd Tanous }, 406daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 4071abe55efSEd Tanous "GetAll", 4081abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 409daf36e2eSEd Tanous return; 410daf36e2eSEd Tanous } 411e0d918bcSEd Tanous 412daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 413f12894f8SJason M. Bills messages::resourceNotFound( 414adbe192aSJason M. Bills asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId); 415daf36e2eSEd Tanous }, 416daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 417daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 418daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 419271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 420c181942fSQiang XU 421c181942fSQiang XU getPhysicalSecurityData(asyncResp); 422e37f8451SRapkiewicz, Pawel } 4231c8fba97SJames Feist 4241c8fba97SJames Feist void doPatch(crow::Response& res, const crow::Request& req, 4251c8fba97SJames Feist const std::vector<std::string>& params) override 4261c8fba97SJames Feist { 4271c8fba97SJames Feist std::optional<std::string> indicatorLed; 4281c8fba97SJames Feist auto asyncResp = std::make_shared<AsyncResp>(res); 4291c8fba97SJames Feist 4301c8fba97SJames Feist if (params.size() != 1) 4311c8fba97SJames Feist { 4321c8fba97SJames Feist return; 4331c8fba97SJames Feist } 4341c8fba97SJames Feist 4351c8fba97SJames Feist if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed)) 4361c8fba97SJames Feist { 4371c8fba97SJames Feist return; 4381c8fba97SJames Feist } 4391c8fba97SJames Feist 4401c8fba97SJames Feist if (!indicatorLed) 4411c8fba97SJames Feist { 4421c8fba97SJames Feist return; // delete this when we support more patch properties 4431c8fba97SJames Feist } 4441c8fba97SJames Feist 4451c8fba97SJames Feist const std::array<const char*, 2> interfaces = { 4461c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 4471c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 4481c8fba97SJames Feist 4491c8fba97SJames Feist const std::string& chassisId = params[0]; 4501c8fba97SJames Feist 4511c8fba97SJames Feist crow::connections::systemBus->async_method_call( 4521c8fba97SJames Feist [asyncResp, chassisId, indicatorLed]( 4531c8fba97SJames Feist const boost::system::error_code ec, 4541c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 4551c8fba97SJames Feist if (ec) 4561c8fba97SJames Feist { 4571c8fba97SJames Feist messages::internalError(asyncResp->res); 4581c8fba97SJames Feist return; 4591c8fba97SJames Feist } 4601c8fba97SJames Feist 4611c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 4621c8fba97SJames Feist for (const std::pair< 4631c8fba97SJames Feist std::string, 4641c8fba97SJames Feist std::vector< 4651214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 4661214b7e7SGunnar Mills object : subtree) 4671c8fba97SJames Feist { 4681c8fba97SJames Feist const std::string& path = object.first; 4691c8fba97SJames Feist const std::vector< 4701214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 4711214b7e7SGunnar Mills connectionNames = object.second; 4721c8fba97SJames Feist 4731c8fba97SJames Feist if (!boost::ends_with(path, chassisId)) 4741c8fba97SJames Feist { 4751c8fba97SJames Feist continue; 4761c8fba97SJames Feist } 4771c8fba97SJames Feist 4781c8fba97SJames Feist if (connectionNames.size() < 1) 4791c8fba97SJames Feist { 4801c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 4811c8fba97SJames Feist continue; 4821c8fba97SJames Feist } 4831c8fba97SJames Feist 4841c8fba97SJames Feist const std::vector<std::string>& interfaces = 4851c8fba97SJames Feist connectionNames[0].second; 4861c8fba97SJames Feist 4871c8fba97SJames Feist if (indicatorLed) 4881c8fba97SJames Feist { 4891c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 4901c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 4911c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board." 4921c8fba97SJames Feist "Motherboard"}; 4931c8fba97SJames Feist bool indicatorChassis = false; 4941c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 4951c8fba97SJames Feist { 4961c8fba97SJames Feist if (std::find(interfaces.begin(), interfaces.end(), 4971c8fba97SJames Feist interface) != interfaces.end()) 4981c8fba97SJames Feist { 4991c8fba97SJames Feist indicatorChassis = true; 5001c8fba97SJames Feist break; 5011c8fba97SJames Feist } 5021c8fba97SJames Feist } 5031c8fba97SJames Feist if (indicatorChassis) 5041c8fba97SJames Feist { 5051c8fba97SJames Feist setIndicatorLedState(asyncResp, 5061c8fba97SJames Feist std::move(*indicatorLed)); 5071c8fba97SJames Feist } 5081c8fba97SJames Feist else 5091c8fba97SJames Feist { 5101c8fba97SJames Feist messages::propertyUnknown(asyncResp->res, 5111c8fba97SJames Feist "IndicatorLED"); 5121c8fba97SJames Feist } 5131c8fba97SJames Feist } 5141c8fba97SJames Feist return; 5151c8fba97SJames Feist } 5161c8fba97SJames Feist 5171c8fba97SJames Feist messages::resourceNotFound( 5181c8fba97SJames Feist asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId); 5191c8fba97SJames Feist }, 5201c8fba97SJames Feist "xyz.openbmc_project.ObjectMapper", 5211c8fba97SJames Feist "/xyz/openbmc_project/object_mapper", 5221c8fba97SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 5231c8fba97SJames Feist "/xyz/openbmc_project/inventory", 0, interfaces); 5241c8fba97SJames Feist } 52562d5e2e4SEd Tanous }; 526dd99e04bSP.K. Lee 527dd99e04bSP.K. Lee void doChassisPowerCycle(std::shared_ptr<AsyncResp> asyncResp) 528dd99e04bSP.K. Lee { 529dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 530dd99e04bSP.K. Lee const char* objectPath = "/xyz/openbmc_project/state/chassis0"; 531dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 532dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 533dd99e04bSP.K. Lee const std::string propertyValue = 534dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 535dd99e04bSP.K. Lee 536dd99e04bSP.K. Lee crow::connections::systemBus->async_method_call( 537dd99e04bSP.K. Lee [asyncResp](const boost::system::error_code ec) { 538dd99e04bSP.K. Lee // Use "Set" method to set the property value. 539dd99e04bSP.K. Lee if (ec) 540dd99e04bSP.K. Lee { 541dd99e04bSP.K. Lee BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec; 542dd99e04bSP.K. Lee messages::internalError(asyncResp->res); 543dd99e04bSP.K. Lee return; 544dd99e04bSP.K. Lee } 545dd99e04bSP.K. Lee 546dd99e04bSP.K. Lee messages::success(asyncResp->res); 547dd99e04bSP.K. Lee }, 548dd99e04bSP.K. Lee processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 549dd99e04bSP.K. Lee interfaceName, destProperty, std::variant<std::string>{propertyValue}); 550dd99e04bSP.K. Lee } 551dd99e04bSP.K. Lee 552dd99e04bSP.K. Lee /** 553dd99e04bSP.K. Lee * ChassisResetAction class supports the POST method for the Reset 554dd99e04bSP.K. Lee * action. 555dd99e04bSP.K. Lee */ 556dd99e04bSP.K. Lee class ChassisResetAction : public Node 557dd99e04bSP.K. Lee { 558dd99e04bSP.K. Lee public: 559dd99e04bSP.K. Lee ChassisResetAction(CrowApp& app) : 560dd99e04bSP.K. Lee Node(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/", 561dd99e04bSP.K. Lee std::string()) 562dd99e04bSP.K. Lee { 563dd99e04bSP.K. Lee entityPrivileges = { 564dd99e04bSP.K. Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 565dd99e04bSP.K. Lee } 566dd99e04bSP.K. Lee 567dd99e04bSP.K. Lee private: 568dd99e04bSP.K. Lee /** 569dd99e04bSP.K. Lee * Function handles POST method request. 570dd99e04bSP.K. Lee * Analyzes POST body before sending Reset request data to D-Bus. 571dd99e04bSP.K. Lee */ 572dd99e04bSP.K. Lee void doPost(crow::Response& res, const crow::Request& req, 573dd99e04bSP.K. Lee const std::vector<std::string>& params) override 574dd99e04bSP.K. Lee { 575dd99e04bSP.K. Lee BMCWEB_LOG_DEBUG << "Post Chassis Reset."; 576dd99e04bSP.K. Lee 577dd99e04bSP.K. Lee std::string resetType; 578dd99e04bSP.K. Lee auto asyncResp = std::make_shared<AsyncResp>(res); 579dd99e04bSP.K. Lee 580dd99e04bSP.K. Lee if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 581dd99e04bSP.K. Lee { 582dd99e04bSP.K. Lee return; 583dd99e04bSP.K. Lee } 584dd99e04bSP.K. Lee 585dd99e04bSP.K. Lee if (resetType != "PowerCycle") 586dd99e04bSP.K. Lee { 587dd99e04bSP.K. Lee BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 588dd99e04bSP.K. Lee << resetType; 589dd99e04bSP.K. Lee messages::actionParameterNotSupported(asyncResp->res, resetType, 590dd99e04bSP.K. Lee "ResetType"); 591dd99e04bSP.K. Lee 592dd99e04bSP.K. Lee return; 593dd99e04bSP.K. Lee } 594dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 595dd99e04bSP.K. Lee } 596dd99e04bSP.K. Lee }; 597*1cb1a9e6SAppaRao Puli 598*1cb1a9e6SAppaRao Puli /** 599*1cb1a9e6SAppaRao Puli * ChassisResetActionInfo derived class for delivering Chassis 600*1cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 601*1cb1a9e6SAppaRao Puli */ 602*1cb1a9e6SAppaRao Puli class ChassisResetActionInfo : public Node 603*1cb1a9e6SAppaRao Puli { 604*1cb1a9e6SAppaRao Puli public: 605*1cb1a9e6SAppaRao Puli /* 606*1cb1a9e6SAppaRao Puli * Default Constructor 607*1cb1a9e6SAppaRao Puli */ 608*1cb1a9e6SAppaRao Puli ChassisResetActionInfo(CrowApp& app) : 609*1cb1a9e6SAppaRao Puli Node(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/", std::string()) 610*1cb1a9e6SAppaRao Puli { 611*1cb1a9e6SAppaRao Puli entityPrivileges = { 612*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 613*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 614*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 615*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 616*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 617*1cb1a9e6SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 618*1cb1a9e6SAppaRao Puli } 619*1cb1a9e6SAppaRao Puli 620*1cb1a9e6SAppaRao Puli private: 621*1cb1a9e6SAppaRao Puli /** 622*1cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 623*1cb1a9e6SAppaRao Puli */ 624*1cb1a9e6SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 625*1cb1a9e6SAppaRao Puli const std::vector<std::string>& params) override 626*1cb1a9e6SAppaRao Puli { 627*1cb1a9e6SAppaRao Puli if (params.size() != 1) 628*1cb1a9e6SAppaRao Puli { 629*1cb1a9e6SAppaRao Puli messages::internalError(res); 630*1cb1a9e6SAppaRao Puli res.end(); 631*1cb1a9e6SAppaRao Puli return; 632*1cb1a9e6SAppaRao Puli } 633*1cb1a9e6SAppaRao Puli const std::string& chassisId = params[0]; 634*1cb1a9e6SAppaRao Puli 635*1cb1a9e6SAppaRao Puli res.jsonValue = {{"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 636*1cb1a9e6SAppaRao Puli {"@odata.id", "/redfish/v1/Chassis/" + chassisId + 637*1cb1a9e6SAppaRao Puli "/ResetActionInfo"}, 638*1cb1a9e6SAppaRao Puli {"Name", "Reset Action Info"}, 639*1cb1a9e6SAppaRao Puli {"Id", "ResetActionInfo"}, 640*1cb1a9e6SAppaRao Puli {"Parameters", 641*1cb1a9e6SAppaRao Puli {{{"Name", "ResetType"}, 642*1cb1a9e6SAppaRao Puli {"Required", true}, 643*1cb1a9e6SAppaRao Puli {"DataType", "String"}, 644*1cb1a9e6SAppaRao Puli {"AllowableValues", {"PowerCycle"}}}}}}; 645*1cb1a9e6SAppaRao Puli res.end(); 646*1cb1a9e6SAppaRao Puli } 647*1cb1a9e6SAppaRao Puli }; 648*1cb1a9e6SAppaRao Puli 649e37f8451SRapkiewicz, Pawel } // namespace redfish 650