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 */ 3623a21a1cSEd Tanous inline 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 8823a21a1cSEd Tanous inline 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 */ 12323a21a1cSEd Tanous inline 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: 16352cc112dSEd Tanous ChassisCollection(App& 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 */ 178cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 179cb13a392SEd Tanous const std::vector<std::string>&) 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; 2074841191fSWludzik, Jozef messages::internalError(asyncResp->res); 2084841191fSWludzik, Jozef return; 2094841191fSWludzik, Jozef } 2104841191fSWludzik, Jozef if ((lastPos + 1) >= objpath.size()) 2114841191fSWludzik, Jozef { 2124841191fSWludzik, Jozef BMCWEB_LOG_ERROR << "Failed to parse path " << objpath; 2134841191fSWludzik, Jozef messages::internalError(asyncResp->res); 2144841191fSWludzik, Jozef return; 21562d5e2e4SEd Tanous } 21662d5e2e4SEd Tanous chassisArray.push_back( 21762d5e2e4SEd Tanous {{"@odata.id", "/redfish/v1/Chassis/" + 21862d5e2e4SEd Tanous objpath.substr(lastPos + 1)}}); 219e37f8451SRapkiewicz, Pawel } 220e37f8451SRapkiewicz, Pawel 22162d5e2e4SEd Tanous asyncResp->res.jsonValue["Members@odata.count"] = 22262d5e2e4SEd Tanous chassisArray.size(); 22362d5e2e4SEd Tanous }, 22462d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", 22562d5e2e4SEd Tanous "/xyz/openbmc_project/object_mapper", 22662d5e2e4SEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 227271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 22862d5e2e4SEd Tanous } 229e37f8451SRapkiewicz, Pawel }; 230e37f8451SRapkiewicz, Pawel 231e37f8451SRapkiewicz, Pawel /** 232e37f8451SRapkiewicz, Pawel * Chassis override class for delivering Chassis Schema 233e37f8451SRapkiewicz, Pawel */ 2341abe55efSEd Tanous class Chassis : public Node 2351abe55efSEd Tanous { 236e37f8451SRapkiewicz, Pawel public: 23752cc112dSEd Tanous Chassis(App& app) : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 2381abe55efSEd Tanous { 239e0d918bcSEd Tanous entityPrivileges = { 240e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 241e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 242e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 243e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 244e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 245e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 246e37f8451SRapkiewicz, Pawel } 247e37f8451SRapkiewicz, Pawel 248e37f8451SRapkiewicz, Pawel private: 249e37f8451SRapkiewicz, Pawel /** 250e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 251e37f8451SRapkiewicz, Pawel */ 252cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 2531abe55efSEd Tanous const std::vector<std::string>& params) override 2541abe55efSEd Tanous { 255adc4f0dbSShawn McCarney const std::array<const char*, 2> interfaces = { 256734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 257adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 258734bfe90SGunnar Mills 259e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 260e37f8451SRapkiewicz, Pawel // impossible. 2611abe55efSEd Tanous if (params.size() != 1) 2621abe55efSEd Tanous { 263f12894f8SJason M. Bills messages::internalError(res); 264e37f8451SRapkiewicz, Pawel res.end(); 265e37f8451SRapkiewicz, Pawel return; 266e37f8451SRapkiewicz, Pawel } 26799cffd7fSShawn McCarney const std::string& chassisId = params[0]; 268e37f8451SRapkiewicz, Pawel 26962d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 27055c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 27162d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 27262d5e2e4SEd Tanous const boost::system::error_code ec, 2731c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 27462d5e2e4SEd Tanous if (ec) 2751abe55efSEd Tanous { 276f12894f8SJason M. Bills messages::internalError(asyncResp->res); 277daf36e2eSEd Tanous return; 278daf36e2eSEd Tanous } 279daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 2801abe55efSEd Tanous for (const std::pair< 2811abe55efSEd Tanous std::string, 2821abe55efSEd Tanous std::vector< 2831214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 2841214b7e7SGunnar Mills object : subtree) 2851abe55efSEd Tanous { 286daf36e2eSEd Tanous const std::string& path = object.first; 2871abe55efSEd Tanous const std::vector< 2881214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 2891214b7e7SGunnar Mills connectionNames = object.second; 290e0d918bcSEd Tanous 2911abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 2921abe55efSEd Tanous { 293daf36e2eSEd Tanous continue; 294daf36e2eSEd Tanous } 29526f03899SShawn McCarney 296b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 297b49ac873SJames Feist 298b49ac873SJames Feist crow::connections::systemBus->async_method_call( 29923a21a1cSEd Tanous [health](const boost::system::error_code ec2, 300b49ac873SJames Feist std::variant<std::vector<std::string>>& resp) { 30123a21a1cSEd Tanous if (ec2) 302b49ac873SJames Feist { 303b49ac873SJames Feist return; // no sensors = no failures 304b49ac873SJames Feist } 305b49ac873SJames Feist std::vector<std::string>* data = 306b49ac873SJames Feist std::get_if<std::vector<std::string>>(&resp); 307b49ac873SJames Feist if (data == nullptr) 308b49ac873SJames Feist { 309b49ac873SJames Feist return; 310b49ac873SJames Feist } 311b49ac873SJames Feist health->inventory = std::move(*data); 312b49ac873SJames Feist }, 313b49ac873SJames Feist "xyz.openbmc_project.ObjectMapper", 314b49ac873SJames Feist path + "/all_sensors", 315b49ac873SJames Feist "org.freedesktop.DBus.Properties", "Get", 316b49ac873SJames Feist "xyz.openbmc_project.Association", "endpoints"); 317b49ac873SJames Feist 318b49ac873SJames Feist health->populate(); 319b49ac873SJames Feist 3201abe55efSEd Tanous if (connectionNames.size() < 1) 3211abe55efSEd Tanous { 3221c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 323e0d918bcSEd Tanous continue; 324daf36e2eSEd Tanous } 325e0d918bcSEd Tanous 32649c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.type"] = 327adbe192aSJason M. Bills "#Chassis.v1_10_0.Chassis"; 32849c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 32949c53ac9SJohnathan Mantey "/redfish/v1/Chassis/" + chassisId; 33049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 33149c53ac9SJohnathan Mantey asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 332dd99e04bSP.K. Lee asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] = { 333dd99e04bSP.K. Lee {"target", "/redfish/v1/Chassis/" + chassisId + 334dd99e04bSP.K. Lee "/Actions/Chassis.Reset"}, 3351cb1a9e6SAppaRao Puli {"@Redfish.ActionInfo", "/redfish/v1/Chassis/" + 3361cb1a9e6SAppaRao Puli chassisId + 3371cb1a9e6SAppaRao Puli "/ResetActionInfo"}}; 338adbe192aSJason M. Bills asyncResp->res.jsonValue["PCIeDevices"] = { 339adbe192aSJason M. Bills {"@odata.id", 340adbe192aSJason M. Bills "/redfish/v1/Systems/system/PCIeDevices"}}; 34149c53ac9SJohnathan Mantey 34249c53ac9SJohnathan Mantey const std::string& connectionName = 34349c53ac9SJohnathan Mantey connectionNames[0].first; 3441c8fba97SJames Feist 34523a21a1cSEd Tanous const std::vector<std::string>& interfaces2 = 3461c8fba97SJames Feist connectionNames[0].second; 3471c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 3481c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 3491c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 3501c8fba97SJames Feist 3511c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 3521c8fba97SJames Feist { 35323a21a1cSEd Tanous if (std::find(interfaces2.begin(), interfaces2.end(), 35423a21a1cSEd Tanous interface) != interfaces2.end()) 3551c8fba97SJames Feist { 3561c8fba97SJames Feist getIndicatorLedState(asyncResp); 3571c8fba97SJames Feist break; 3581c8fba97SJames Feist } 3591c8fba97SJames Feist } 3601c8fba97SJames Feist 36155c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 36262d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 36390728b54SEd Tanous const boost::system::error_code /*ec2*/, 3641abe55efSEd Tanous const std::vector<std::pair< 3651abe55efSEd Tanous std::string, VariantType>>& propertiesList) { 3661214b7e7SGunnar Mills for (const std::pair<std::string, VariantType>& 3671214b7e7SGunnar Mills property : propertiesList) 3681abe55efSEd Tanous { 36999cffd7fSShawn McCarney // Store DBus properties that are also Redfish 37099cffd7fSShawn McCarney // properties with same name and a string value 37199cffd7fSShawn McCarney const std::string& propertyName = 37299cffd7fSShawn McCarney property.first; 37399cffd7fSShawn McCarney if ((propertyName == "PartNumber") || 37499cffd7fSShawn McCarney (propertyName == "SerialNumber") || 37599cffd7fSShawn McCarney (propertyName == "Manufacturer") || 37699cffd7fSShawn McCarney (propertyName == "Model")) 37799cffd7fSShawn McCarney { 378daf36e2eSEd Tanous const std::string* value = 37999cffd7fSShawn McCarney std::get_if<std::string>( 38099cffd7fSShawn McCarney &property.second); 3811abe55efSEd Tanous if (value != nullptr) 3821abe55efSEd Tanous { 38399cffd7fSShawn McCarney asyncResp->res.jsonValue[propertyName] = 38462d5e2e4SEd Tanous *value; 385daf36e2eSEd Tanous } 386daf36e2eSEd Tanous } 38799cffd7fSShawn McCarney } 38862d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 38962d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 39062d5e2e4SEd Tanous asyncResp->res.jsonValue["Thermal"] = { 3911abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3921abe55efSEd Tanous chassisId + "/Thermal"}}; 3932474adfaSEd Tanous // Power object 3942474adfaSEd Tanous asyncResp->res.jsonValue["Power"] = { 3952474adfaSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3962474adfaSEd Tanous chassisId + "/Power"}}; 39795a3ecadSAnthony Wilson // SensorCollection 39895a3ecadSAnthony Wilson asyncResp->res.jsonValue["Sensors"] = { 39995a3ecadSAnthony Wilson {"@odata.id", "/redfish/v1/Chassis/" + 40095a3ecadSAnthony Wilson chassisId + "/Sensors"}}; 401029573d4SEd Tanous asyncResp->res.jsonValue["Status"] = { 402029573d4SEd Tanous {"State", "Enabled"}, 403029573d4SEd Tanous }; 4042474adfaSEd Tanous 405029573d4SEd Tanous asyncResp->res 406029573d4SEd Tanous .jsonValue["Links"]["ComputerSystems"] = { 407029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Systems/system"}}}; 408029573d4SEd Tanous asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 409029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 410beeca0aeSGunnar Mills getChassisState(asyncResp); 411daf36e2eSEd Tanous }, 412daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 4131abe55efSEd Tanous "GetAll", 4141abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 415daf36e2eSEd Tanous return; 416daf36e2eSEd Tanous } 417e0d918bcSEd Tanous 418daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 419f12894f8SJason M. Bills messages::resourceNotFound( 420adbe192aSJason M. Bills asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId); 421daf36e2eSEd Tanous }, 422daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 423daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 424daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 425271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 426c181942fSQiang XU 427c181942fSQiang XU getPhysicalSecurityData(asyncResp); 428e37f8451SRapkiewicz, Pawel } 4291c8fba97SJames Feist 4301c8fba97SJames Feist void doPatch(crow::Response& res, const crow::Request& req, 4311c8fba97SJames Feist const std::vector<std::string>& params) override 4321c8fba97SJames Feist { 4331c8fba97SJames Feist std::optional<std::string> indicatorLed; 4341c8fba97SJames Feist auto asyncResp = std::make_shared<AsyncResp>(res); 4351c8fba97SJames Feist 4361c8fba97SJames Feist if (params.size() != 1) 4371c8fba97SJames Feist { 4381c8fba97SJames Feist return; 4391c8fba97SJames Feist } 4401c8fba97SJames Feist 4411c8fba97SJames Feist if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed)) 4421c8fba97SJames Feist { 4431c8fba97SJames Feist return; 4441c8fba97SJames Feist } 4451c8fba97SJames Feist 4461c8fba97SJames Feist if (!indicatorLed) 4471c8fba97SJames Feist { 4481c8fba97SJames Feist return; // delete this when we support more patch properties 4491c8fba97SJames Feist } 4501c8fba97SJames Feist 4511c8fba97SJames Feist const std::array<const char*, 2> interfaces = { 4521c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 4531c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 4541c8fba97SJames Feist 4551c8fba97SJames Feist const std::string& chassisId = params[0]; 4561c8fba97SJames Feist 4571c8fba97SJames Feist crow::connections::systemBus->async_method_call( 4581c8fba97SJames Feist [asyncResp, chassisId, indicatorLed]( 4591c8fba97SJames Feist const boost::system::error_code ec, 4601c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 4611c8fba97SJames Feist if (ec) 4621c8fba97SJames Feist { 4631c8fba97SJames Feist messages::internalError(asyncResp->res); 4641c8fba97SJames Feist return; 4651c8fba97SJames Feist } 4661c8fba97SJames Feist 4671c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 4681c8fba97SJames Feist for (const std::pair< 4691c8fba97SJames Feist std::string, 4701c8fba97SJames Feist std::vector< 4711214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 4721214b7e7SGunnar Mills object : subtree) 4731c8fba97SJames Feist { 4741c8fba97SJames Feist const std::string& path = object.first; 4751c8fba97SJames Feist const std::vector< 4761214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 4771214b7e7SGunnar Mills connectionNames = object.second; 4781c8fba97SJames Feist 4791c8fba97SJames Feist if (!boost::ends_with(path, chassisId)) 4801c8fba97SJames Feist { 4811c8fba97SJames Feist continue; 4821c8fba97SJames Feist } 4831c8fba97SJames Feist 4841c8fba97SJames Feist if (connectionNames.size() < 1) 4851c8fba97SJames Feist { 4861c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 4871c8fba97SJames Feist continue; 4881c8fba97SJames Feist } 4891c8fba97SJames Feist 49023a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 4911c8fba97SJames Feist connectionNames[0].second; 4921c8fba97SJames Feist 4931c8fba97SJames Feist if (indicatorLed) 4941c8fba97SJames Feist { 4951c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 4961c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 4971c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board." 4981c8fba97SJames Feist "Motherboard"}; 4991c8fba97SJames Feist bool indicatorChassis = false; 5001c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 5011c8fba97SJames Feist { 50223a21a1cSEd Tanous if (std::find(interfaces3.begin(), 50323a21a1cSEd Tanous interfaces3.end(), 50423a21a1cSEd Tanous interface) != interfaces3.end()) 5051c8fba97SJames Feist { 5061c8fba97SJames Feist indicatorChassis = true; 5071c8fba97SJames Feist break; 5081c8fba97SJames Feist } 5091c8fba97SJames Feist } 5101c8fba97SJames Feist if (indicatorChassis) 5111c8fba97SJames Feist { 5121c8fba97SJames Feist setIndicatorLedState(asyncResp, 5131c8fba97SJames Feist std::move(*indicatorLed)); 5141c8fba97SJames Feist } 5151c8fba97SJames Feist else 5161c8fba97SJames Feist { 5171c8fba97SJames Feist messages::propertyUnknown(asyncResp->res, 5181c8fba97SJames Feist "IndicatorLED"); 5191c8fba97SJames Feist } 5201c8fba97SJames Feist } 5211c8fba97SJames Feist return; 5221c8fba97SJames Feist } 5231c8fba97SJames Feist 5241c8fba97SJames Feist messages::resourceNotFound( 5251c8fba97SJames Feist asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId); 5261c8fba97SJames Feist }, 5271c8fba97SJames Feist "xyz.openbmc_project.ObjectMapper", 5281c8fba97SJames Feist "/xyz/openbmc_project/object_mapper", 5291c8fba97SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", 5301c8fba97SJames Feist "/xyz/openbmc_project/inventory", 0, interfaces); 5311c8fba97SJames Feist } 53262d5e2e4SEd Tanous }; 533dd99e04bSP.K. Lee 534b5a76932SEd Tanous inline void doChassisPowerCycle(const std::shared_ptr<AsyncResp>& asyncResp) 535dd99e04bSP.K. Lee { 536*c3b3c92aSVijay Khemka const char* busName = "xyz.openbmc_project.ObjectMapper"; 537*c3b3c92aSVijay Khemka const char* path = "/xyz/openbmc_project/object_mapper"; 538*c3b3c92aSVijay Khemka const char* interface = "xyz.openbmc_project.ObjectMapper"; 539*c3b3c92aSVijay Khemka const char* method = "GetSubTreePaths"; 540*c3b3c92aSVijay Khemka 541*c3b3c92aSVijay Khemka const std::array<const char*, 1> interfaces = { 542*c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 543*c3b3c92aSVijay Khemka 544*c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 545*c3b3c92aSVijay Khemka crow::connections::systemBus->async_method_call( 546*c3b3c92aSVijay Khemka [asyncResp](const boost::system::error_code ec, 547*c3b3c92aSVijay Khemka const std::vector<std::string>& chassisList) { 548*c3b3c92aSVijay Khemka if (ec) 549*c3b3c92aSVijay Khemka { 550*c3b3c92aSVijay Khemka BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec; 551*c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 552*c3b3c92aSVijay Khemka return; 553*c3b3c92aSVijay Khemka } 554*c3b3c92aSVijay Khemka 555dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 556dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 557dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 558dd99e04bSP.K. Lee const std::string propertyValue = 559dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 560*c3b3c92aSVijay Khemka std::string objectPath = 561*c3b3c92aSVijay Khemka "/xyz/openbmc_project/state/chassis_system0"; 562*c3b3c92aSVijay Khemka 563*c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 564*c3b3c92aSVijay Khemka if ((std::find(chassisList.begin(), chassisList.end(), 565*c3b3c92aSVijay Khemka objectPath)) == chassisList.end()) 566*c3b3c92aSVijay Khemka { 567*c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 568*c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 569*c3b3c92aSVijay Khemka */ 570*c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 571*c3b3c92aSVijay Khemka } 572dd99e04bSP.K. Lee 573dd99e04bSP.K. Lee crow::connections::systemBus->async_method_call( 574dd99e04bSP.K. Lee [asyncResp](const boost::system::error_code ec) { 575dd99e04bSP.K. Lee // Use "Set" method to set the property value. 576dd99e04bSP.K. Lee if (ec) 577dd99e04bSP.K. Lee { 578*c3b3c92aSVijay Khemka BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " 579*c3b3c92aSVijay Khemka << ec; 580dd99e04bSP.K. Lee messages::internalError(asyncResp->res); 581dd99e04bSP.K. Lee return; 582dd99e04bSP.K. Lee } 583dd99e04bSP.K. Lee 584dd99e04bSP.K. Lee messages::success(asyncResp->res); 585dd99e04bSP.K. Lee }, 586*c3b3c92aSVijay Khemka processName, objectPath, "org.freedesktop.DBus.Properties", 587*c3b3c92aSVijay Khemka "Set", interfaceName, destProperty, 588*c3b3c92aSVijay Khemka std::variant<std::string>{propertyValue}); 589*c3b3c92aSVijay Khemka }, 590*c3b3c92aSVijay Khemka busName, path, interface, method, "/", 0, interfaces); 591dd99e04bSP.K. Lee } 592dd99e04bSP.K. Lee 593dd99e04bSP.K. Lee /** 594dd99e04bSP.K. Lee * ChassisResetAction class supports the POST method for the Reset 595dd99e04bSP.K. Lee * action. 596dd99e04bSP.K. Lee */ 597dd99e04bSP.K. Lee class ChassisResetAction : public Node 598dd99e04bSP.K. Lee { 599dd99e04bSP.K. Lee public: 60052cc112dSEd Tanous ChassisResetAction(App& app) : 601dd99e04bSP.K. Lee Node(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/", 602dd99e04bSP.K. Lee std::string()) 603dd99e04bSP.K. Lee { 604dd99e04bSP.K. Lee entityPrivileges = { 605dd99e04bSP.K. Lee {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 606dd99e04bSP.K. Lee } 607dd99e04bSP.K. Lee 608dd99e04bSP.K. Lee private: 609dd99e04bSP.K. Lee /** 610dd99e04bSP.K. Lee * Function handles POST method request. 611dd99e04bSP.K. Lee * Analyzes POST body before sending Reset request data to D-Bus. 612dd99e04bSP.K. Lee */ 613dd99e04bSP.K. Lee void doPost(crow::Response& res, const crow::Request& req, 614cb13a392SEd Tanous const std::vector<std::string>&) override 615dd99e04bSP.K. Lee { 616dd99e04bSP.K. Lee BMCWEB_LOG_DEBUG << "Post Chassis Reset."; 617dd99e04bSP.K. Lee 618dd99e04bSP.K. Lee std::string resetType; 619dd99e04bSP.K. Lee auto asyncResp = std::make_shared<AsyncResp>(res); 620dd99e04bSP.K. Lee 621dd99e04bSP.K. Lee if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 622dd99e04bSP.K. Lee { 623dd99e04bSP.K. Lee return; 624dd99e04bSP.K. Lee } 625dd99e04bSP.K. Lee 626dd99e04bSP.K. Lee if (resetType != "PowerCycle") 627dd99e04bSP.K. Lee { 628dd99e04bSP.K. Lee BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 629dd99e04bSP.K. Lee << resetType; 630dd99e04bSP.K. Lee messages::actionParameterNotSupported(asyncResp->res, resetType, 631dd99e04bSP.K. Lee "ResetType"); 632dd99e04bSP.K. Lee 633dd99e04bSP.K. Lee return; 634dd99e04bSP.K. Lee } 635dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 636dd99e04bSP.K. Lee } 637dd99e04bSP.K. Lee }; 6381cb1a9e6SAppaRao Puli 6391cb1a9e6SAppaRao Puli /** 6401cb1a9e6SAppaRao Puli * ChassisResetActionInfo derived class for delivering Chassis 6411cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 6421cb1a9e6SAppaRao Puli */ 6431cb1a9e6SAppaRao Puli class ChassisResetActionInfo : public Node 6441cb1a9e6SAppaRao Puli { 6451cb1a9e6SAppaRao Puli public: 6461cb1a9e6SAppaRao Puli /* 6471cb1a9e6SAppaRao Puli * Default Constructor 6481cb1a9e6SAppaRao Puli */ 64952cc112dSEd Tanous ChassisResetActionInfo(App& app) : 6501cb1a9e6SAppaRao Puli Node(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/", std::string()) 6511cb1a9e6SAppaRao Puli { 6521cb1a9e6SAppaRao Puli entityPrivileges = { 6531cb1a9e6SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 6541cb1a9e6SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 6551cb1a9e6SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 6561cb1a9e6SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 6571cb1a9e6SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 6581cb1a9e6SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 6591cb1a9e6SAppaRao Puli } 6601cb1a9e6SAppaRao Puli 6611cb1a9e6SAppaRao Puli private: 6621cb1a9e6SAppaRao Puli /** 6631cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 6641cb1a9e6SAppaRao Puli */ 665cb13a392SEd Tanous void doGet(crow::Response& res, const crow::Request&, 6661cb1a9e6SAppaRao Puli const std::vector<std::string>& params) override 6671cb1a9e6SAppaRao Puli { 6681cb1a9e6SAppaRao Puli if (params.size() != 1) 6691cb1a9e6SAppaRao Puli { 6701cb1a9e6SAppaRao Puli messages::internalError(res); 6711cb1a9e6SAppaRao Puli res.end(); 6721cb1a9e6SAppaRao Puli return; 6731cb1a9e6SAppaRao Puli } 6741cb1a9e6SAppaRao Puli const std::string& chassisId = params[0]; 6751cb1a9e6SAppaRao Puli 6761cb1a9e6SAppaRao Puli res.jsonValue = {{"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 6771cb1a9e6SAppaRao Puli {"@odata.id", "/redfish/v1/Chassis/" + chassisId + 6781cb1a9e6SAppaRao Puli "/ResetActionInfo"}, 6791cb1a9e6SAppaRao Puli {"Name", "Reset Action Info"}, 6801cb1a9e6SAppaRao Puli {"Id", "ResetActionInfo"}, 6811cb1a9e6SAppaRao Puli {"Parameters", 6821cb1a9e6SAppaRao Puli {{{"Name", "ResetType"}, 6831cb1a9e6SAppaRao Puli {"Required", true}, 6841cb1a9e6SAppaRao Puli {"DataType", "String"}, 6851cb1a9e6SAppaRao Puli {"AllowableValues", {"PowerCycle"}}}}}}; 6861cb1a9e6SAppaRao Puli res.end(); 6871cb1a9e6SAppaRao Puli } 6881cb1a9e6SAppaRao Puli }; 6891cb1a9e6SAppaRao Puli 690e37f8451SRapkiewicz, Pawel } // namespace redfish 691