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 */ 36*23a21a1cSEd 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 88*23a21a1cSEd 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 */ 123*23a21a1cSEd 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 */ 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: 23052cc112dSEd Tanous Chassis(App& app) : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) 2311abe55efSEd Tanous { 232e0d918bcSEd Tanous entityPrivileges = { 233e0d918bcSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 234e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 235e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 236e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 237e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 238e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 239e37f8451SRapkiewicz, Pawel } 240e37f8451SRapkiewicz, Pawel 241e37f8451SRapkiewicz, Pawel private: 242e37f8451SRapkiewicz, Pawel /** 243e37f8451SRapkiewicz, Pawel * Functions triggers appropriate requests on DBus 244e37f8451SRapkiewicz, Pawel */ 24555c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 2461abe55efSEd Tanous const std::vector<std::string>& params) override 2471abe55efSEd Tanous { 248adc4f0dbSShawn McCarney const std::array<const char*, 2> interfaces = { 249734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 250adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 251734bfe90SGunnar Mills 252e37f8451SRapkiewicz, Pawel // Check if there is required param, truly entering this shall be 253e37f8451SRapkiewicz, Pawel // impossible. 2541abe55efSEd Tanous if (params.size() != 1) 2551abe55efSEd Tanous { 256f12894f8SJason M. Bills messages::internalError(res); 257e37f8451SRapkiewicz, Pawel res.end(); 258e37f8451SRapkiewicz, Pawel return; 259e37f8451SRapkiewicz, Pawel } 26099cffd7fSShawn McCarney const std::string& chassisId = params[0]; 261e37f8451SRapkiewicz, Pawel 26262d5e2e4SEd Tanous auto asyncResp = std::make_shared<AsyncResp>(res); 26355c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 26462d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 26562d5e2e4SEd Tanous const boost::system::error_code ec, 2661c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 26762d5e2e4SEd Tanous if (ec) 2681abe55efSEd Tanous { 269f12894f8SJason M. Bills messages::internalError(asyncResp->res); 270daf36e2eSEd Tanous return; 271daf36e2eSEd Tanous } 272daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 2731abe55efSEd Tanous for (const std::pair< 2741abe55efSEd Tanous std::string, 2751abe55efSEd Tanous std::vector< 2761214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 2771214b7e7SGunnar Mills object : subtree) 2781abe55efSEd Tanous { 279daf36e2eSEd Tanous const std::string& path = object.first; 2801abe55efSEd Tanous const std::vector< 2811214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 2821214b7e7SGunnar Mills connectionNames = object.second; 283e0d918bcSEd Tanous 2841abe55efSEd Tanous if (!boost::ends_with(path, chassisId)) 2851abe55efSEd Tanous { 286daf36e2eSEd Tanous continue; 287daf36e2eSEd Tanous } 28826f03899SShawn McCarney 289b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 290b49ac873SJames Feist 291b49ac873SJames Feist crow::connections::systemBus->async_method_call( 292*23a21a1cSEd Tanous [health](const boost::system::error_code ec2, 293b49ac873SJames Feist std::variant<std::vector<std::string>>& resp) { 294*23a21a1cSEd Tanous if (ec2) 295b49ac873SJames Feist { 296b49ac873SJames Feist return; // no sensors = no failures 297b49ac873SJames Feist } 298b49ac873SJames Feist std::vector<std::string>* data = 299b49ac873SJames Feist std::get_if<std::vector<std::string>>(&resp); 300b49ac873SJames Feist if (data == nullptr) 301b49ac873SJames Feist { 302b49ac873SJames Feist return; 303b49ac873SJames Feist } 304b49ac873SJames Feist health->inventory = std::move(*data); 305b49ac873SJames Feist }, 306b49ac873SJames Feist "xyz.openbmc_project.ObjectMapper", 307b49ac873SJames Feist path + "/all_sensors", 308b49ac873SJames Feist "org.freedesktop.DBus.Properties", "Get", 309b49ac873SJames Feist "xyz.openbmc_project.Association", "endpoints"); 310b49ac873SJames Feist 311b49ac873SJames Feist health->populate(); 312b49ac873SJames Feist 3131abe55efSEd Tanous if (connectionNames.size() < 1) 3141abe55efSEd Tanous { 3151c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 316e0d918bcSEd Tanous continue; 317daf36e2eSEd Tanous } 318e0d918bcSEd Tanous 31949c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.type"] = 320adbe192aSJason M. Bills "#Chassis.v1_10_0.Chassis"; 32149c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 32249c53ac9SJohnathan Mantey "/redfish/v1/Chassis/" + chassisId; 32349c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 32449c53ac9SJohnathan Mantey asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 325dd99e04bSP.K. Lee asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] = { 326dd99e04bSP.K. Lee {"target", "/redfish/v1/Chassis/" + chassisId + 327dd99e04bSP.K. Lee "/Actions/Chassis.Reset"}, 3281cb1a9e6SAppaRao Puli {"@Redfish.ActionInfo", "/redfish/v1/Chassis/" + 3291cb1a9e6SAppaRao Puli chassisId + 3301cb1a9e6SAppaRao Puli "/ResetActionInfo"}}; 331adbe192aSJason M. Bills asyncResp->res.jsonValue["PCIeDevices"] = { 332adbe192aSJason M. Bills {"@odata.id", 333adbe192aSJason M. Bills "/redfish/v1/Systems/system/PCIeDevices"}}; 33449c53ac9SJohnathan Mantey 33549c53ac9SJohnathan Mantey const std::string& connectionName = 33649c53ac9SJohnathan Mantey connectionNames[0].first; 3371c8fba97SJames Feist 338*23a21a1cSEd Tanous const std::vector<std::string>& interfaces2 = 3391c8fba97SJames Feist connectionNames[0].second; 3401c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 3411c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 3421c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 3431c8fba97SJames Feist 3441c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 3451c8fba97SJames Feist { 346*23a21a1cSEd Tanous if (std::find(interfaces2.begin(), interfaces2.end(), 347*23a21a1cSEd Tanous interface) != interfaces2.end()) 3481c8fba97SJames Feist { 3491c8fba97SJames Feist getIndicatorLedState(asyncResp); 3501c8fba97SJames Feist break; 3511c8fba97SJames Feist } 3521c8fba97SJames Feist } 3531c8fba97SJames Feist 35455c7b7a2SEd Tanous crow::connections::systemBus->async_method_call( 35562d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 356*23a21a1cSEd Tanous const boost::system::error_code ec2, 3571abe55efSEd Tanous const std::vector<std::pair< 3581abe55efSEd Tanous std::string, VariantType>>& propertiesList) { 3591214b7e7SGunnar Mills for (const std::pair<std::string, VariantType>& 3601214b7e7SGunnar Mills property : propertiesList) 3611abe55efSEd Tanous { 36299cffd7fSShawn McCarney // Store DBus properties that are also Redfish 36399cffd7fSShawn McCarney // properties with same name and a string value 36499cffd7fSShawn McCarney const std::string& propertyName = 36599cffd7fSShawn McCarney property.first; 36699cffd7fSShawn McCarney if ((propertyName == "PartNumber") || 36799cffd7fSShawn McCarney (propertyName == "SerialNumber") || 36899cffd7fSShawn McCarney (propertyName == "Manufacturer") || 36999cffd7fSShawn McCarney (propertyName == "Model")) 37099cffd7fSShawn McCarney { 371daf36e2eSEd Tanous const std::string* value = 37299cffd7fSShawn McCarney std::get_if<std::string>( 37399cffd7fSShawn McCarney &property.second); 3741abe55efSEd Tanous if (value != nullptr) 3751abe55efSEd Tanous { 37699cffd7fSShawn McCarney asyncResp->res.jsonValue[propertyName] = 37762d5e2e4SEd Tanous *value; 378daf36e2eSEd Tanous } 379daf36e2eSEd Tanous } 38099cffd7fSShawn McCarney } 38162d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 38262d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 38362d5e2e4SEd Tanous asyncResp->res.jsonValue["Thermal"] = { 3841abe55efSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3851abe55efSEd Tanous chassisId + "/Thermal"}}; 3862474adfaSEd Tanous // Power object 3872474adfaSEd Tanous asyncResp->res.jsonValue["Power"] = { 3882474adfaSEd Tanous {"@odata.id", "/redfish/v1/Chassis/" + 3892474adfaSEd Tanous chassisId + "/Power"}}; 39095a3ecadSAnthony Wilson // SensorCollection 39195a3ecadSAnthony Wilson asyncResp->res.jsonValue["Sensors"] = { 39295a3ecadSAnthony Wilson {"@odata.id", "/redfish/v1/Chassis/" + 39395a3ecadSAnthony Wilson chassisId + "/Sensors"}}; 394029573d4SEd Tanous asyncResp->res.jsonValue["Status"] = { 395029573d4SEd Tanous {"State", "Enabled"}, 396029573d4SEd Tanous }; 3972474adfaSEd Tanous 398029573d4SEd Tanous asyncResp->res 399029573d4SEd Tanous .jsonValue["Links"]["ComputerSystems"] = { 400029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Systems/system"}}}; 401029573d4SEd Tanous asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 402029573d4SEd Tanous {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 403beeca0aeSGunnar Mills getChassisState(asyncResp); 404daf36e2eSEd Tanous }, 405daf36e2eSEd Tanous connectionName, path, "org.freedesktop.DBus.Properties", 4061abe55efSEd Tanous "GetAll", 4071abe55efSEd Tanous "xyz.openbmc_project.Inventory.Decorator.Asset"); 408daf36e2eSEd Tanous return; 409daf36e2eSEd Tanous } 410e0d918bcSEd Tanous 411daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 412f12894f8SJason M. Bills messages::resourceNotFound( 413adbe192aSJason M. Bills asyncResp->res, "#Chassis.v1_10_0.Chassis", chassisId); 414daf36e2eSEd Tanous }, 415daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", 416daf36e2eSEd Tanous "/xyz/openbmc_project/object_mapper", 417daf36e2eSEd Tanous "xyz.openbmc_project.ObjectMapper", "GetSubTree", 418271584abSEd Tanous "/xyz/openbmc_project/inventory", 0, interfaces); 419c181942fSQiang XU 420c181942fSQiang XU getPhysicalSecurityData(asyncResp); 421e37f8451SRapkiewicz, Pawel } 4221c8fba97SJames Feist 4231c8fba97SJames Feist void doPatch(crow::Response& res, const crow::Request& req, 4241c8fba97SJames Feist const std::vector<std::string>& params) override 4251c8fba97SJames Feist { 4261c8fba97SJames Feist std::optional<std::string> indicatorLed; 4271c8fba97SJames Feist auto asyncResp = std::make_shared<AsyncResp>(res); 4281c8fba97SJames Feist 4291c8fba97SJames Feist if (params.size() != 1) 4301c8fba97SJames Feist { 4311c8fba97SJames Feist return; 4321c8fba97SJames Feist } 4331c8fba97SJames Feist 4341c8fba97SJames Feist if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed)) 4351c8fba97SJames Feist { 4361c8fba97SJames Feist return; 4371c8fba97SJames Feist } 4381c8fba97SJames Feist 4391c8fba97SJames Feist if (!indicatorLed) 4401c8fba97SJames Feist { 4411c8fba97SJames Feist return; // delete this when we support more patch properties 4421c8fba97SJames Feist } 4431c8fba97SJames Feist 4441c8fba97SJames Feist const std::array<const char*, 2> interfaces = { 4451c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 4461c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 4471c8fba97SJames Feist 4481c8fba97SJames Feist const std::string& chassisId = params[0]; 4491c8fba97SJames Feist 4501c8fba97SJames Feist crow::connections::systemBus->async_method_call( 4511c8fba97SJames Feist [asyncResp, chassisId, indicatorLed]( 4521c8fba97SJames Feist const boost::system::error_code ec, 4531c8fba97SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 4541c8fba97SJames Feist if (ec) 4551c8fba97SJames Feist { 4561c8fba97SJames Feist messages::internalError(asyncResp->res); 4571c8fba97SJames Feist return; 4581c8fba97SJames Feist } 4591c8fba97SJames Feist 4601c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 4611c8fba97SJames Feist for (const std::pair< 4621c8fba97SJames Feist std::string, 4631c8fba97SJames Feist std::vector< 4641214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>>& 4651214b7e7SGunnar Mills object : subtree) 4661c8fba97SJames Feist { 4671c8fba97SJames Feist const std::string& path = object.first; 4681c8fba97SJames Feist const std::vector< 4691214b7e7SGunnar Mills std::pair<std::string, std::vector<std::string>>>& 4701214b7e7SGunnar Mills connectionNames = object.second; 4711c8fba97SJames Feist 4721c8fba97SJames Feist if (!boost::ends_with(path, chassisId)) 4731c8fba97SJames Feist { 4741c8fba97SJames Feist continue; 4751c8fba97SJames Feist } 4761c8fba97SJames Feist 4771c8fba97SJames Feist if (connectionNames.size() < 1) 4781c8fba97SJames Feist { 4791c8fba97SJames Feist BMCWEB_LOG_ERROR << "Got 0 Connection names"; 4801c8fba97SJames Feist continue; 4811c8fba97SJames Feist } 4821c8fba97SJames Feist 483*23a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 4841c8fba97SJames Feist connectionNames[0].second; 4851c8fba97SJames Feist 4861c8fba97SJames Feist if (indicatorLed) 4871c8fba97SJames Feist { 4881c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 4891c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 4901c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board." 4911c8fba97SJames Feist "Motherboard"}; 4921c8fba97SJames Feist bool indicatorChassis = false; 4931c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 4941c8fba97SJames Feist { 495*23a21a1cSEd Tanous if (std::find(interfaces3.begin(), 496*23a21a1cSEd Tanous interfaces3.end(), 497*23a21a1cSEd Tanous interface) != interfaces3.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 527*23a21a1cSEd Tanous inline 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: 55952cc112dSEd Tanous ChassisResetAction(App& 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 }; 5971cb1a9e6SAppaRao Puli 5981cb1a9e6SAppaRao Puli /** 5991cb1a9e6SAppaRao Puli * ChassisResetActionInfo derived class for delivering Chassis 6001cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 6011cb1a9e6SAppaRao Puli */ 6021cb1a9e6SAppaRao Puli class ChassisResetActionInfo : public Node 6031cb1a9e6SAppaRao Puli { 6041cb1a9e6SAppaRao Puli public: 6051cb1a9e6SAppaRao Puli /* 6061cb1a9e6SAppaRao Puli * Default Constructor 6071cb1a9e6SAppaRao Puli */ 60852cc112dSEd Tanous ChassisResetActionInfo(App& app) : 6091cb1a9e6SAppaRao Puli Node(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/", std::string()) 6101cb1a9e6SAppaRao Puli { 6111cb1a9e6SAppaRao Puli entityPrivileges = { 6121cb1a9e6SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 6131cb1a9e6SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 6141cb1a9e6SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 6151cb1a9e6SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 6161cb1a9e6SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 6171cb1a9e6SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 6181cb1a9e6SAppaRao Puli } 6191cb1a9e6SAppaRao Puli 6201cb1a9e6SAppaRao Puli private: 6211cb1a9e6SAppaRao Puli /** 6221cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 6231cb1a9e6SAppaRao Puli */ 6241cb1a9e6SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 6251cb1a9e6SAppaRao Puli const std::vector<std::string>& params) override 6261cb1a9e6SAppaRao Puli { 6271cb1a9e6SAppaRao Puli if (params.size() != 1) 6281cb1a9e6SAppaRao Puli { 6291cb1a9e6SAppaRao Puli messages::internalError(res); 6301cb1a9e6SAppaRao Puli res.end(); 6311cb1a9e6SAppaRao Puli return; 6321cb1a9e6SAppaRao Puli } 6331cb1a9e6SAppaRao Puli const std::string& chassisId = params[0]; 6341cb1a9e6SAppaRao Puli 6351cb1a9e6SAppaRao Puli res.jsonValue = {{"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 6361cb1a9e6SAppaRao Puli {"@odata.id", "/redfish/v1/Chassis/" + chassisId + 6371cb1a9e6SAppaRao Puli "/ResetActionInfo"}, 6381cb1a9e6SAppaRao Puli {"Name", "Reset Action Info"}, 6391cb1a9e6SAppaRao Puli {"Id", "ResetActionInfo"}, 6401cb1a9e6SAppaRao Puli {"Parameters", 6411cb1a9e6SAppaRao Puli {{{"Name", "ResetType"}, 6421cb1a9e6SAppaRao Puli {"Required", true}, 6431cb1a9e6SAppaRao Puli {"DataType", "String"}, 6441cb1a9e6SAppaRao Puli {"AllowableValues", {"PowerCycle"}}}}}}; 6451cb1a9e6SAppaRao Puli res.end(); 6461cb1a9e6SAppaRao Puli } 6471cb1a9e6SAppaRao Puli }; 6481cb1a9e6SAppaRao Puli 649e37f8451SRapkiewicz, Pawel } // namespace redfish 650