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 1813451e39SWilly Tu #include "bmcweb_config.h" 1913451e39SWilly Tu 203ccb3adbSEd Tanous #include "app.hpp" 217a1dbc48SGeorge Liu #include "dbus_utility.hpp" 22b49ac873SJames Feist #include "health.hpp" 231c8fba97SJames Feist #include "led.hpp" 243ccb3adbSEd Tanous #include "query.hpp" 253ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 263ccb3adbSEd Tanous #include "utils/collection.hpp" 273ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 28cf7eba09SNan Zhou #include "utils/json_utils.hpp" 291abe55efSEd Tanous 30e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 31ef4c65b7SEd Tanous #include <boost/url/format.hpp> 321e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp> 33fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp> 3486d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 351214b7e7SGunnar Mills 367a1dbc48SGeorge Liu #include <array> 377a1dbc48SGeorge Liu #include <string_view> 387a1dbc48SGeorge Liu 391abe55efSEd Tanous namespace redfish 401abe55efSEd Tanous { 41e37f8451SRapkiewicz, Pawel 42e37f8451SRapkiewicz, Pawel /** 435e577bc1SWilly Tu * @brief Retrieves resources over dbus to link to the chassis 445e577bc1SWilly Tu * 455e577bc1SWilly Tu * @param[in] asyncResp - Shared pointer for completing asynchronous 465e577bc1SWilly Tu * calls 475e577bc1SWilly Tu * @param[in] path - Chassis dbus path to look for the storage. 485e577bc1SWilly Tu * 495e577bc1SWilly Tu * Calls the Association endpoints on the path + "/storage" and add the link of 505e577bc1SWilly Tu * json["Links"]["Storage@odata.count"] = 515e577bc1SWilly Tu * {"@odata.id", "/redfish/v1/Storage/" + resourceId} 525e577bc1SWilly Tu * 535e577bc1SWilly Tu * @return None. 545e577bc1SWilly Tu */ 555e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 565e577bc1SWilly Tu const sdbusplus::message::object_path& path) 575e577bc1SWilly Tu { 585e577bc1SWilly Tu sdbusplus::asio::getProperty<std::vector<std::string>>( 595e577bc1SWilly Tu *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper", 605e577bc1SWilly Tu (path / "storage").str, "xyz.openbmc_project.Association", "endpoints", 61d4b054c1SWilly Tu [asyncResp](const boost::system::error_code& ec, 625e577bc1SWilly Tu const std::vector<std::string>& storageList) { 635e577bc1SWilly Tu if (ec) 645e577bc1SWilly Tu { 65*62598e31SEd Tanous BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error"); 665e577bc1SWilly Tu return; 675e577bc1SWilly Tu } 685e577bc1SWilly Tu 695e577bc1SWilly Tu nlohmann::json::array_t storages; 705e577bc1SWilly Tu for (const std::string& storagePath : storageList) 715e577bc1SWilly Tu { 725e577bc1SWilly Tu std::string id = 735e577bc1SWilly Tu sdbusplus::message::object_path(storagePath).filename(); 745e577bc1SWilly Tu if (id.empty()) 755e577bc1SWilly Tu { 765e577bc1SWilly Tu continue; 775e577bc1SWilly Tu } 785e577bc1SWilly Tu 795e577bc1SWilly Tu nlohmann::json::object_t storage; 805e577bc1SWilly Tu storage["@odata.id"] = boost::urls::format( 815e577bc1SWilly Tu "/redfish/v1/Systems/system/Storage/{}", id); 825e577bc1SWilly Tu storages.emplace_back(std::move(storage)); 835e577bc1SWilly Tu } 845e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage@odata.count"] = 855e577bc1SWilly Tu storages.size(); 865e577bc1SWilly Tu asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages); 875e577bc1SWilly Tu }); 885e577bc1SWilly Tu } 895e577bc1SWilly Tu 905e577bc1SWilly Tu /** 91beeca0aeSGunnar Mills * @brief Retrieves chassis state properties over dbus 92beeca0aeSGunnar Mills * 93ac106bf6SEd Tanous * @param[in] asyncResp - Shared pointer for completing asynchronous calls. 94beeca0aeSGunnar Mills * 95beeca0aeSGunnar Mills * @return None. 96beeca0aeSGunnar Mills */ 97ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 98beeca0aeSGunnar Mills { 991e1e598dSJonathan Doman // crow::connections::systemBus->async_method_call( 1001e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 1011e1e598dSJonathan Doman *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 1021e1e598dSJonathan Doman "/xyz/openbmc_project/state/chassis0", 1031e1e598dSJonathan Doman "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 104ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1051e1e598dSJonathan Doman const std::string& chassisState) { 106beeca0aeSGunnar Mills if (ec) 107beeca0aeSGunnar Mills { 108a6e5e0abSCarson Labrado if (ec == boost::system::errc::host_unreachable) 109a6e5e0abSCarson Labrado { 110a6e5e0abSCarson Labrado // Service not available, no error, just don't return 111a6e5e0abSCarson Labrado // chassis state info 112*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Service not available {}", ec); 113a6e5e0abSCarson Labrado return; 114a6e5e0abSCarson Labrado } 115*62598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 116ac106bf6SEd Tanous messages::internalError(asyncResp->res); 117beeca0aeSGunnar Mills return; 118beeca0aeSGunnar Mills } 119beeca0aeSGunnar Mills 120*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState); 121beeca0aeSGunnar Mills // Verify Chassis State 122002d39b4SEd Tanous if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On") 123beeca0aeSGunnar Mills { 124ac106bf6SEd Tanous asyncResp->res.jsonValue["PowerState"] = "On"; 125ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 126beeca0aeSGunnar Mills } 1271e1e598dSJonathan Doman else if (chassisState == 128beeca0aeSGunnar Mills "xyz.openbmc_project.State.Chassis.PowerState.Off") 129beeca0aeSGunnar Mills { 130ac106bf6SEd Tanous asyncResp->res.jsonValue["PowerState"] = "Off"; 131ac106bf6SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 132beeca0aeSGunnar Mills } 1331e1e598dSJonathan Doman }); 134beeca0aeSGunnar Mills } 135beeca0aeSGunnar Mills 136ac106bf6SEd Tanous inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> asyncResp, 137c181942fSQiang XU const std::string& service, 138c181942fSQiang XU const std::string& objPath) 139c181942fSQiang XU { 140*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Get intrusion status by service "); 141c181942fSQiang XU 1421e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 1431e1e598dSJonathan Doman *crow::connections::systemBus, service, objPath, 1441e1e598dSJonathan Doman "xyz.openbmc_project.Chassis.Intrusion", "Status", 145ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec, 1461e1e598dSJonathan Doman const std::string& value) { 147c181942fSQiang XU if (ec) 148c181942fSQiang XU { 1494e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 150c181942fSQiang XU // mandatory property 151*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 152c181942fSQiang XU return; 153c181942fSQiang XU } 154c181942fSQiang XU 155ac106bf6SEd Tanous asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 156ac106bf6SEd Tanous 1; 157ac106bf6SEd Tanous asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value; 1581e1e598dSJonathan Doman }); 159c181942fSQiang XU } 160c181942fSQiang XU 161c181942fSQiang XU /** 162c181942fSQiang XU * Retrieves physical security properties over dbus 163c181942fSQiang XU */ 164ac106bf6SEd Tanous inline void 165ac106bf6SEd Tanous getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 166c181942fSQiang XU { 167e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 168e99073f5SGeorge Liu "xyz.openbmc_project.Chassis.Intrusion"}; 169e99073f5SGeorge Liu dbus::utility::getSubTree( 170e99073f5SGeorge Liu "/xyz/openbmc_project/Intrusion", 1, interfaces, 171ac106bf6SEd Tanous [asyncResp{std::move(asyncResp)}]( 172e99073f5SGeorge Liu const boost::system::error_code& ec, 173b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 174c181942fSQiang XU if (ec) 175c181942fSQiang XU { 1764e0453b1SGunnar Mills // do not add err msg in redfish response, because this is not 177c181942fSQiang XU // mandatory property 178*62598e31SEd Tanous BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec); 179c181942fSQiang XU return; 180c181942fSQiang XU } 181c181942fSQiang XU // Iterate over all retrieved ObjectPaths. 182c181942fSQiang XU for (const auto& object : subtree) 183c181942fSQiang XU { 184840a9ffcSPatrick Williams if (!object.second.empty()) 185c181942fSQiang XU { 186840a9ffcSPatrick Williams const auto service = object.second.front(); 187ac106bf6SEd Tanous getIntrusionByService(asyncResp, service.first, object.first); 188c181942fSQiang XU return; 189c181942fSQiang XU } 190c181942fSQiang XU } 191e99073f5SGeorge Liu }); 192c181942fSQiang XU } 193c181942fSQiang XU 194cf7eba09SNan Zhou inline void handleChassisCollectionGet( 195cf7eba09SNan Zhou App& app, const crow::Request& req, 196cf7eba09SNan Zhou const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1971abe55efSEd Tanous { 1983ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19945ca1b86SEd Tanous { 20045ca1b86SEd Tanous return; 20145ca1b86SEd Tanous } 2028d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 2038d1b46d7Szhanghch05 "#ChassisCollection.ChassisCollection"; 2048d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 2058d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 206e37f8451SRapkiewicz, Pawel 2077a1dbc48SGeorge Liu constexpr std::array<std::string_view, 2> interfaces{ 2087a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board", 2097a1dbc48SGeorge Liu "xyz.openbmc_project.Inventory.Item.Chassis"}; 21002f6ff19SGunnar Mills collection_util::getCollectionMembers( 2117a1dbc48SGeorge Liu asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces); 212cf7eba09SNan Zhou } 213cf7eba09SNan Zhou 214a5617496SJie Yang inline void getChassisContainedBy( 215a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 216a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 217a5617496SJie Yang const dbus::utility::MapperEndPoints& upstreamChassisPaths) 218a5617496SJie Yang { 219a5617496SJie Yang if (ec) 220a5617496SJie Yang { 221a5617496SJie Yang if (ec.value() != EBADR) 222a5617496SJie Yang { 223*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 224a5617496SJie Yang messages::internalError(asyncResp->res); 225a5617496SJie Yang } 226a5617496SJie Yang return; 227a5617496SJie Yang } 228a5617496SJie Yang if (upstreamChassisPaths.empty()) 229a5617496SJie Yang { 230a5617496SJie Yang return; 231a5617496SJie Yang } 232a5617496SJie Yang if (upstreamChassisPaths.size() > 1) 233a5617496SJie Yang { 234*62598e31SEd Tanous BMCWEB_LOG_ERROR("{} is contained by mutliple chassis", chassisId); 235a5617496SJie Yang messages::internalError(asyncResp->res); 236a5617496SJie Yang return; 237a5617496SJie Yang } 238a5617496SJie Yang 239a5617496SJie Yang sdbusplus::message::object_path upstreamChassisPath( 240a5617496SJie Yang upstreamChassisPaths[0]); 241a5617496SJie Yang std::string upstreamChassis = upstreamChassisPath.filename(); 242a5617496SJie Yang if (upstreamChassis.empty()) 243a5617496SJie Yang { 244*62598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}", 245*62598e31SEd Tanous upstreamChassisPath.str, chassisId); 246a5617496SJie Yang return; 247a5617496SJie Yang } 248a5617496SJie Yang 249a5617496SJie Yang asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] = 250a5617496SJie Yang boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis); 251a5617496SJie Yang } 252a5617496SJie Yang 253a5617496SJie Yang inline void getChassisContains( 254a5617496SJie Yang const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 255a5617496SJie Yang const std::string& chassisId, const boost::system::error_code& ec, 256a5617496SJie Yang const dbus::utility::MapperEndPoints& downstreamChassisPaths) 257a5617496SJie Yang { 258a5617496SJie Yang if (ec) 259a5617496SJie Yang { 260a5617496SJie Yang if (ec.value() != EBADR) 261a5617496SJie Yang { 262*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 263a5617496SJie Yang messages::internalError(asyncResp->res); 264a5617496SJie Yang } 265a5617496SJie Yang return; 266a5617496SJie Yang } 267a5617496SJie Yang if (downstreamChassisPaths.empty()) 268a5617496SJie Yang { 269a5617496SJie Yang return; 270a5617496SJie Yang } 271a5617496SJie Yang nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"]; 272a5617496SJie Yang if (!jValue.is_array()) 273a5617496SJie Yang { 274a5617496SJie Yang // Create the array if it was empty 275a5617496SJie Yang jValue = nlohmann::json::array(); 276a5617496SJie Yang } 277a5617496SJie Yang for (const auto& p : downstreamChassisPaths) 278a5617496SJie Yang { 279a5617496SJie Yang sdbusplus::message::object_path downstreamChassisPath(p); 280a5617496SJie Yang std::string downstreamChassis = downstreamChassisPath.filename(); 281a5617496SJie Yang if (downstreamChassis.empty()) 282a5617496SJie Yang { 283*62598e31SEd Tanous BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}", 284*62598e31SEd Tanous downstreamChassisPath.str, chassisId); 285a5617496SJie Yang continue; 286a5617496SJie Yang } 287a5617496SJie Yang nlohmann::json link; 288a5617496SJie Yang link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", 289a5617496SJie Yang downstreamChassis); 290a5617496SJie Yang jValue.push_back(std::move(link)); 291a5617496SJie Yang } 292a5617496SJie Yang asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size(); 293a5617496SJie Yang } 294a5617496SJie Yang 295a5617496SJie Yang inline void 296a5617496SJie Yang getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297a5617496SJie Yang const std::string& chassisId, 298a5617496SJie Yang const std::string& chassisPath) 299a5617496SJie Yang { 300*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Get chassis connectivity"); 301a5617496SJie Yang 302a5617496SJie Yang dbus::utility::getAssociationEndPoints( 303a5617496SJie Yang chassisPath + "/contained_by", 304a5617496SJie Yang std::bind_front(getChassisContainedBy, asyncResp, chassisId)); 305a5617496SJie Yang 306a5617496SJie Yang dbus::utility::getAssociationEndPoints( 307a5617496SJie Yang chassisPath + "/containing", 308a5617496SJie Yang std::bind_front(getChassisContains, asyncResp, chassisId)); 309a5617496SJie Yang } 310a5617496SJie Yang 311cf7eba09SNan Zhou /** 312cf7eba09SNan Zhou * ChassisCollection derived class for delivering Chassis Collection Schema 313cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 314cf7eba09SNan Zhou */ 315cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app) 316cf7eba09SNan Zhou { 317cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 318cf7eba09SNan Zhou .privileges(redfish::privileges::getChassisCollection) 319cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 320cf7eba09SNan Zhou std::bind_front(handleChassisCollectionGet, std::ref(app))); 32162d5e2e4SEd Tanous } 322e37f8451SRapkiewicz, Pawel 323308f70c7SWilly Tu inline void 324308f70c7SWilly Tu getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 325308f70c7SWilly Tu const std::string& connectionName, 326308f70c7SWilly Tu const std::string& path) 327308f70c7SWilly Tu { 3281e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 3291e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 3301e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 3315e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3321e1e598dSJonathan Doman const std::string& property) { 333308f70c7SWilly Tu if (ec) 334308f70c7SWilly Tu { 335*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location"); 336308f70c7SWilly Tu messages::internalError(asyncResp->res); 337308f70c7SWilly Tu return; 338308f70c7SWilly Tu } 339308f70c7SWilly Tu 340002d39b4SEd Tanous asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 3411e1e598dSJonathan Doman property; 3421e1e598dSJonathan Doman }); 343308f70c7SWilly Tu } 344308f70c7SWilly Tu 345308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 346308f70c7SWilly Tu const std::string& connectionName, 347308f70c7SWilly Tu const std::string& path) 348308f70c7SWilly Tu { 3491e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 3501e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 3511e1e598dSJonathan Doman "xyz.openbmc_project.Common.UUID", "UUID", 3525e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec, 3531e1e598dSJonathan Doman const std::string& chassisUUID) { 354308f70c7SWilly Tu if (ec) 355308f70c7SWilly Tu { 356*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for UUID"); 357308f70c7SWilly Tu messages::internalError(asyncResp->res); 358308f70c7SWilly Tu return; 359308f70c7SWilly Tu } 3601e1e598dSJonathan Doman asyncResp->res.jsonValue["UUID"] = chassisUUID; 3611e1e598dSJonathan Doman }); 362308f70c7SWilly Tu } 363308f70c7SWilly Tu 364cf7eba09SNan Zhou inline void 365cf7eba09SNan Zhou handleChassisGet(App& app, const crow::Request& req, 36645ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 367cf7eba09SNan Zhou const std::string& chassisId) 368cf7eba09SNan Zhou { 3693ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 37045ca1b86SEd Tanous { 37145ca1b86SEd Tanous return; 37245ca1b86SEd Tanous } 373e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 374734bfe90SGunnar Mills "xyz.openbmc_project.Inventory.Item.Board", 375adc4f0dbSShawn McCarney "xyz.openbmc_project.Inventory.Item.Chassis"}; 376734bfe90SGunnar Mills 377e99073f5SGeorge Liu dbus::utility::getSubTree( 378e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 37962d5e2e4SEd Tanous [asyncResp, chassisId(std::string(chassisId))]( 380e99073f5SGeorge Liu const boost::system::error_code& ec, 381b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 38262d5e2e4SEd Tanous if (ec) 3831abe55efSEd Tanous { 384*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 385f12894f8SJason M. Bills messages::internalError(asyncResp->res); 386daf36e2eSEd Tanous return; 387daf36e2eSEd Tanous } 388daf36e2eSEd Tanous // Iterate over all retrieved ObjectPaths. 389cf7eba09SNan Zhou for (const std::pair< 390cf7eba09SNan Zhou std::string, 391cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 3921214b7e7SGunnar Mills object : subtree) 3931abe55efSEd Tanous { 394daf36e2eSEd Tanous const std::string& path = object.first; 395cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 3961214b7e7SGunnar Mills connectionNames = object.second; 3977e860f15SJohn Edward Broadbent 398997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 399997093ebSGeorge Liu if (objPath.filename() != chassisId) 4001abe55efSEd Tanous { 401daf36e2eSEd Tanous continue; 402daf36e2eSEd Tanous } 40326f03899SShawn McCarney 404a5617496SJie Yang getChassisConnectivity(asyncResp, chassisId, path); 405a5617496SJie Yang 406002d39b4SEd Tanous auto health = std::make_shared<HealthPopulate>(asyncResp); 407b49ac873SJames Feist 40813451e39SWilly Tu if constexpr (bmcwebEnableHealthPopulate) 40913451e39SWilly Tu { 4106c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 4116c3e9451SGeorge Liu path + "/all_sensors", 4125e7e2dc5SEd Tanous [health](const boost::system::error_code& ec2, 4136c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 41423a21a1cSEd Tanous if (ec2) 415b49ac873SJames Feist { 416b49ac873SJames Feist return; // no sensors = no failures 417b49ac873SJames Feist } 4181e1e598dSJonathan Doman health->inventory = resp; 4191e1e598dSJonathan Doman }); 420b49ac873SJames Feist 421b49ac873SJames Feist health->populate(); 42213451e39SWilly Tu } 423b49ac873SJames Feist 42426f6976fSEd Tanous if (connectionNames.empty()) 4251abe55efSEd Tanous { 426*62598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 427e0d918bcSEd Tanous continue; 428daf36e2eSEd Tanous } 429e0d918bcSEd Tanous 43049c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.type"] = 431523d4868SLogananth Sundararaj "#Chassis.v1_22_0.Chassis"; 43249c53ac9SJohnathan Mantey asyncResp->res.jsonValue["@odata.id"] = 433ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 43449c53ac9SJohnathan Mantey asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 43549c53ac9SJohnathan Mantey asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 436cf7eba09SNan Zhou asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 437ef4c65b7SEd Tanous boost::urls::format( 438ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId); 4391476687dSEd Tanous asyncResp->res 440cf7eba09SNan Zhou .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 441ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 442ef4c65b7SEd Tanous chassisId); 4431476687dSEd Tanous asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] = 444ef4c65b7SEd Tanous "/redfish/v1/Systems/system/PCIeDevices"; 44549c53ac9SJohnathan Mantey 4466c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 4476c3e9451SGeorge Liu path + "/drive", 4486c3e9451SGeorge Liu [asyncResp, 4496c3e9451SGeorge Liu chassisId](const boost::system::error_code& ec3, 4506c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& resp) { 45192903bd4SJohn Edward Broadbent if (ec3 || resp.empty()) 45292903bd4SJohn Edward Broadbent { 45392903bd4SJohn Edward Broadbent return; // no drives = no failures 45492903bd4SJohn Edward Broadbent } 45592903bd4SJohn Edward Broadbent 45692903bd4SJohn Edward Broadbent nlohmann::json reference; 457ef4c65b7SEd Tanous reference["@odata.id"] = boost::urls::format( 458ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/Drives", chassisId); 45992903bd4SJohn Edward Broadbent asyncResp->res.jsonValue["Drives"] = std::move(reference); 46092903bd4SJohn Edward Broadbent }); 46192903bd4SJohn Edward Broadbent 462002d39b4SEd Tanous const std::string& connectionName = connectionNames[0].first; 4631c8fba97SJames Feist 46423a21a1cSEd Tanous const std::vector<std::string>& interfaces2 = 4651c8fba97SJames Feist connectionNames[0].second; 4661c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 4671c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 4680fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 4691c8fba97SJames Feist 470476b9cc5STejas Patil const std::string assetTagInterface = 4710fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 472523d4868SLogananth Sundararaj const std::string replaceableInterface = 473523d4868SLogananth Sundararaj "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 474523d4868SLogananth Sundararaj for (const auto& interface : interfaces2) 475523d4868SLogananth Sundararaj { 476523d4868SLogananth Sundararaj if (interface == assetTagInterface) 477476b9cc5STejas Patil { 4781e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 479002d39b4SEd Tanous *crow::connections::systemBus, connectionName, path, 480002d39b4SEd Tanous assetTagInterface, "AssetTag", 481523d4868SLogananth Sundararaj [asyncResp, 482523d4868SLogananth Sundararaj chassisId](const boost::system::error_code& ec2, 4831e1e598dSJonathan Doman const std::string& property) { 4848a592810SEd Tanous if (ec2) 485476b9cc5STejas Patil { 486*62598e31SEd Tanous BMCWEB_LOG_ERROR( 487*62598e31SEd Tanous "DBus response error for AssetTag: {}", ec2); 488476b9cc5STejas Patil messages::internalError(asyncResp->res); 489476b9cc5STejas Patil return; 490476b9cc5STejas Patil } 491002d39b4SEd Tanous asyncResp->res.jsonValue["AssetTag"] = property; 4921e1e598dSJonathan Doman }); 493476b9cc5STejas Patil } 494523d4868SLogananth Sundararaj else if (interface == replaceableInterface) 495523d4868SLogananth Sundararaj { 496523d4868SLogananth Sundararaj sdbusplus::asio::getProperty<bool>( 497523d4868SLogananth Sundararaj *crow::connections::systemBus, connectionName, path, 498523d4868SLogananth Sundararaj replaceableInterface, "HotPluggable", 499523d4868SLogananth Sundararaj [asyncResp, 500523d4868SLogananth Sundararaj chassisId](const boost::system::error_code& ec2, 501523d4868SLogananth Sundararaj const bool property) { 502523d4868SLogananth Sundararaj if (ec2) 503523d4868SLogananth Sundararaj { 504*62598e31SEd Tanous BMCWEB_LOG_ERROR( 505*62598e31SEd Tanous "DBus response error for HotPluggable: {}", 506*62598e31SEd Tanous ec2); 507523d4868SLogananth Sundararaj messages::internalError(asyncResp->res); 508523d4868SLogananth Sundararaj return; 509523d4868SLogananth Sundararaj } 510523d4868SLogananth Sundararaj asyncResp->res.jsonValue["HotPluggable"] = property; 511523d4868SLogananth Sundararaj }); 512523d4868SLogananth Sundararaj } 513523d4868SLogananth Sundararaj } 514476b9cc5STejas Patil 5151c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 5161c8fba97SJames Feist { 517002d39b4SEd Tanous if (std::find(interfaces2.begin(), interfaces2.end(), 51823a21a1cSEd Tanous interface) != interfaces2.end()) 5191c8fba97SJames Feist { 5201c8fba97SJames Feist getIndicatorLedState(asyncResp); 5219f8bfa7cSGunnar Mills getLocationIndicatorActive(asyncResp); 5221c8fba97SJames Feist break; 5231c8fba97SJames Feist } 5241c8fba97SJames Feist } 5251c8fba97SJames Feist 52686d89ed7SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 52786d89ed7SKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 52886d89ed7SKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 5295e577bc1SWilly Tu [asyncResp, chassisId(std::string(chassisId)), 5305e577bc1SWilly Tu path](const boost::system::error_code& /*ec2*/, 531cf7eba09SNan Zhou const dbus::utility::DBusPropertiesMap& propertiesList) { 53286d89ed7SKrzysztof Grobelny const std::string* partNumber = nullptr; 53386d89ed7SKrzysztof Grobelny const std::string* serialNumber = nullptr; 53486d89ed7SKrzysztof Grobelny const std::string* manufacturer = nullptr; 53586d89ed7SKrzysztof Grobelny const std::string* model = nullptr; 53686d89ed7SKrzysztof Grobelny const std::string* sparePartNumber = nullptr; 53786d89ed7SKrzysztof Grobelny 53886d89ed7SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 53986d89ed7SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 54086d89ed7SKrzysztof Grobelny "PartNumber", partNumber, "SerialNumber", serialNumber, 54186d89ed7SKrzysztof Grobelny "Manufacturer", manufacturer, "Model", model, 54286d89ed7SKrzysztof Grobelny "SparePartNumber", sparePartNumber); 54386d89ed7SKrzysztof Grobelny 54486d89ed7SKrzysztof Grobelny if (!success) 5451abe55efSEd Tanous { 546002d39b4SEd Tanous messages::internalError(asyncResp->res); 547caa11f7aSAlpana Kumari return; 548daf36e2eSEd Tanous } 54986d89ed7SKrzysztof Grobelny 55086d89ed7SKrzysztof Grobelny if (partNumber != nullptr) 55186d89ed7SKrzysztof Grobelny { 55286d89ed7SKrzysztof Grobelny asyncResp->res.jsonValue["PartNumber"] = *partNumber; 55386d89ed7SKrzysztof Grobelny } 55486d89ed7SKrzysztof Grobelny 55586d89ed7SKrzysztof Grobelny if (serialNumber != nullptr) 55686d89ed7SKrzysztof Grobelny { 55786d89ed7SKrzysztof Grobelny asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 55886d89ed7SKrzysztof Grobelny } 55986d89ed7SKrzysztof Grobelny 56086d89ed7SKrzysztof Grobelny if (manufacturer != nullptr) 56186d89ed7SKrzysztof Grobelny { 56286d89ed7SKrzysztof Grobelny asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 56386d89ed7SKrzysztof Grobelny } 56486d89ed7SKrzysztof Grobelny 56586d89ed7SKrzysztof Grobelny if (model != nullptr) 56686d89ed7SKrzysztof Grobelny { 56786d89ed7SKrzysztof Grobelny asyncResp->res.jsonValue["Model"] = *model; 56886d89ed7SKrzysztof Grobelny } 56986d89ed7SKrzysztof Grobelny 570caa11f7aSAlpana Kumari // SparePartNumber is optional on D-Bus 571caa11f7aSAlpana Kumari // so skip if it is empty 57286d89ed7SKrzysztof Grobelny if (sparePartNumber != nullptr && !sparePartNumber->empty()) 573caa11f7aSAlpana Kumari { 57486d89ed7SKrzysztof Grobelny asyncResp->res.jsonValue["SparePartNumber"] = 57586d89ed7SKrzysztof Grobelny *sparePartNumber; 576caa11f7aSAlpana Kumari } 57786d89ed7SKrzysztof Grobelny 57862d5e2e4SEd Tanous asyncResp->res.jsonValue["Name"] = chassisId; 57962d5e2e4SEd Tanous asyncResp->res.jsonValue["Id"] = chassisId; 5800256b694Szhanghch05 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL 581002d39b4SEd Tanous asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 582ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Thermal", 583ef4c65b7SEd Tanous chassisId); 5842474adfaSEd Tanous // Power object 5851476687dSEd Tanous asyncResp->res.jsonValue["Power"]["@odata.id"] = 586ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Power", 587ef4c65b7SEd Tanous chassisId); 5880256b694Szhanghch05 #endif 5892973963eSXiaochao Ma #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM 5902973963eSXiaochao Ma asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 591ef4c65b7SEd Tanous boost::urls::format( 592ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId); 59377b36437SChicago Duan asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 594ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 595ef4c65b7SEd Tanous chassisId); 5964ca3ec3cSAlbert Zhang asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 597ef4c65b7SEd Tanous boost::urls::format( 598ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId); 5992973963eSXiaochao Ma #endif 60095a3ecadSAnthony Wilson // SensorCollection 601002d39b4SEd Tanous asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 602ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}/Sensors", 603ef4c65b7SEd Tanous chassisId); 604002d39b4SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 6051476687dSEd Tanous 6061476687dSEd Tanous nlohmann::json::array_t computerSystems; 6071476687dSEd Tanous nlohmann::json::object_t system; 608002d39b4SEd Tanous system["@odata.id"] = "/redfish/v1/Systems/system"; 609ad539545SPatrick Williams computerSystems.emplace_back(std::move(system)); 610002d39b4SEd Tanous asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 6111476687dSEd Tanous std::move(computerSystems); 6121476687dSEd Tanous 6131476687dSEd Tanous nlohmann::json::array_t managedBy; 6141476687dSEd Tanous nlohmann::json::object_t manager; 615002d39b4SEd Tanous manager["@odata.id"] = "/redfish/v1/Managers/bmc"; 616ad539545SPatrick Williams managedBy.emplace_back(std::move(manager)); 6177e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Links"]["ManagedBy"] = 6181476687dSEd Tanous std::move(managedBy); 619beeca0aeSGunnar Mills getChassisState(asyncResp); 6205e577bc1SWilly Tu getStorageLink(asyncResp, path); 62186d89ed7SKrzysztof Grobelny }); 6222c37b4b0SSharad Yadav 623308f70c7SWilly Tu for (const auto& interface : interfaces2) 6242c37b4b0SSharad Yadav { 625308f70c7SWilly Tu if (interface == "xyz.openbmc_project.Common.UUID") 6262c37b4b0SSharad Yadav { 627308f70c7SWilly Tu getChassisUUID(asyncResp, connectionName, path); 6282c37b4b0SSharad Yadav } 629cf7eba09SNan Zhou else if (interface == 6300fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 6312c37b4b0SSharad Yadav { 632002d39b4SEd Tanous getChassisLocationCode(asyncResp, connectionName, path); 6332c37b4b0SSharad Yadav } 6342c37b4b0SSharad Yadav } 6352c37b4b0SSharad Yadav 636daf36e2eSEd Tanous return; 637daf36e2eSEd Tanous } 638e0d918bcSEd Tanous 639daf36e2eSEd Tanous // Couldn't find an object with that name. return an error 640d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 641e99073f5SGeorge Liu }); 642c181942fSQiang XU 643c181942fSQiang XU getPhysicalSecurityData(asyncResp); 644cf7eba09SNan Zhou } 6451c8fba97SJames Feist 646cf7eba09SNan Zhou inline void 647cf7eba09SNan Zhou handleChassisPatch(App& app, const crow::Request& req, 6487e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 649cf7eba09SNan Zhou const std::string& param) 650cf7eba09SNan Zhou { 6513ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 65245ca1b86SEd Tanous { 65345ca1b86SEd Tanous return; 65445ca1b86SEd Tanous } 6559f8bfa7cSGunnar Mills std::optional<bool> locationIndicatorActive; 6561c8fba97SJames Feist std::optional<std::string> indicatorLed; 6571c8fba97SJames Feist 6587e860f15SJohn Edward Broadbent if (param.empty()) 6591c8fba97SJames Feist { 6601c8fba97SJames Feist return; 6611c8fba97SJames Feist } 6621c8fba97SJames Feist 66315ed6780SWilly Tu if (!json_util::readJsonPatch( 6647e860f15SJohn Edward Broadbent req, asyncResp->res, "LocationIndicatorActive", 6657e860f15SJohn Edward Broadbent locationIndicatorActive, "IndicatorLED", indicatorLed)) 6661c8fba97SJames Feist { 6671c8fba97SJames Feist return; 6681c8fba97SJames Feist } 6691c8fba97SJames Feist 6709f8bfa7cSGunnar Mills // TODO (Gunnar): Remove IndicatorLED after enough time has passed 6719f8bfa7cSGunnar Mills if (!locationIndicatorActive && !indicatorLed) 6721c8fba97SJames Feist { 6731c8fba97SJames Feist return; // delete this when we support more patch properties 6741c8fba97SJames Feist } 675d6aa0093SGunnar Mills if (indicatorLed) 676d6aa0093SGunnar Mills { 6777e860f15SJohn Edward Broadbent asyncResp->res.addHeader( 6787e860f15SJohn Edward Broadbent boost::beast::http::field::warning, 6790fda0f12SGeorge Liu "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 680d6aa0093SGunnar Mills } 6811c8fba97SJames Feist 682e99073f5SGeorge Liu constexpr std::array<std::string_view, 2> interfaces = { 6831c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Board", 6841c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Chassis"}; 6851c8fba97SJames Feist 6867e860f15SJohn Edward Broadbent const std::string& chassisId = param; 6871c8fba97SJames Feist 688e99073f5SGeorge Liu dbus::utility::getSubTree( 689e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 690cf7eba09SNan Zhou [asyncResp, chassisId, locationIndicatorActive, 6915e7e2dc5SEd Tanous indicatorLed](const boost::system::error_code& ec, 692b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 6931c8fba97SJames Feist if (ec) 6941c8fba97SJames Feist { 695*62598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error {}", ec); 6961c8fba97SJames Feist messages::internalError(asyncResp->res); 6971c8fba97SJames Feist return; 6981c8fba97SJames Feist } 6991c8fba97SJames Feist 7001c8fba97SJames Feist // Iterate over all retrieved ObjectPaths. 701cf7eba09SNan Zhou for (const std::pair< 702cf7eba09SNan Zhou std::string, 703cf7eba09SNan Zhou std::vector<std::pair<std::string, std::vector<std::string>>>>& 7041214b7e7SGunnar Mills object : subtree) 7051c8fba97SJames Feist { 7061c8fba97SJames Feist const std::string& path = object.first; 707cf7eba09SNan Zhou const std::vector<std::pair<std::string, std::vector<std::string>>>& 7081214b7e7SGunnar Mills connectionNames = object.second; 7091c8fba97SJames Feist 710997093ebSGeorge Liu sdbusplus::message::object_path objPath(path); 711997093ebSGeorge Liu if (objPath.filename() != chassisId) 7121c8fba97SJames Feist { 7131c8fba97SJames Feist continue; 7141c8fba97SJames Feist } 7151c8fba97SJames Feist 71626f6976fSEd Tanous if (connectionNames.empty()) 7171c8fba97SJames Feist { 718*62598e31SEd Tanous BMCWEB_LOG_ERROR("Got 0 Connection names"); 7191c8fba97SJames Feist continue; 7201c8fba97SJames Feist } 7211c8fba97SJames Feist 72223a21a1cSEd Tanous const std::vector<std::string>& interfaces3 = 7231c8fba97SJames Feist connectionNames[0].second; 7241c8fba97SJames Feist 7251c8fba97SJames Feist const std::array<const char*, 2> hasIndicatorLed = { 7261c8fba97SJames Feist "xyz.openbmc_project.Inventory.Item.Panel", 7270fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 7281c8fba97SJames Feist bool indicatorChassis = false; 7291c8fba97SJames Feist for (const char* interface : hasIndicatorLed) 7301c8fba97SJames Feist { 731002d39b4SEd Tanous if (std::find(interfaces3.begin(), interfaces3.end(), 73223a21a1cSEd Tanous interface) != interfaces3.end()) 7331c8fba97SJames Feist { 7341c8fba97SJames Feist indicatorChassis = true; 7351c8fba97SJames Feist break; 7361c8fba97SJames Feist } 7371c8fba97SJames Feist } 7389f8bfa7cSGunnar Mills if (locationIndicatorActive) 7399f8bfa7cSGunnar Mills { 7409f8bfa7cSGunnar Mills if (indicatorChassis) 7419f8bfa7cSGunnar Mills { 742002d39b4SEd Tanous setLocationIndicatorActive(asyncResp, 743002d39b4SEd Tanous *locationIndicatorActive); 7449f8bfa7cSGunnar Mills } 7459f8bfa7cSGunnar Mills else 7469f8bfa7cSGunnar Mills { 747002d39b4SEd Tanous messages::propertyUnknown(asyncResp->res, 748002d39b4SEd Tanous "LocationIndicatorActive"); 7499f8bfa7cSGunnar Mills } 7509f8bfa7cSGunnar Mills } 7519f8bfa7cSGunnar Mills if (indicatorLed) 7529f8bfa7cSGunnar Mills { 7531c8fba97SJames Feist if (indicatorChassis) 7541c8fba97SJames Feist { 755f23b7296SEd Tanous setIndicatorLedState(asyncResp, *indicatorLed); 7561c8fba97SJames Feist } 7571c8fba97SJames Feist else 7581c8fba97SJames Feist { 759cf7eba09SNan Zhou messages::propertyUnknown(asyncResp->res, "IndicatorLED"); 7601c8fba97SJames Feist } 7611c8fba97SJames Feist } 7621c8fba97SJames Feist return; 7631c8fba97SJames Feist } 7641c8fba97SJames Feist 765d8a5d5d8SJiaqing Zhao messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 766e99073f5SGeorge Liu }); 767cf7eba09SNan Zhou } 768cf7eba09SNan Zhou 769cf7eba09SNan Zhou /** 770cf7eba09SNan Zhou * Chassis override class for delivering Chassis Schema 771cf7eba09SNan Zhou * Functions triggers appropriate requests on DBus 772cf7eba09SNan Zhou */ 773cf7eba09SNan Zhou inline void requestRoutesChassis(App& app) 774cf7eba09SNan Zhou { 775cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 776cf7eba09SNan Zhou .privileges(redfish::privileges::getChassis) 777cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 778cf7eba09SNan Zhou std::bind_front(handleChassisGet, std::ref(app))); 779cf7eba09SNan Zhou 780cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 781cf7eba09SNan Zhou .privileges(redfish::privileges::patchChassis) 782cf7eba09SNan Zhou .methods(boost::beast::http::verb::patch)( 783cf7eba09SNan Zhou std::bind_front(handleChassisPatch, std::ref(app))); 7841c8fba97SJames Feist } 785dd99e04bSP.K. Lee 786fc903b3dSAndrew Geissler /** 787fc903b3dSAndrew Geissler * Handle error responses from d-bus for chassis power cycles 788fc903b3dSAndrew Geissler */ 789fc903b3dSAndrew Geissler inline void handleChassisPowerCycleError(const boost::system::error_code& ec, 790fc903b3dSAndrew Geissler const sdbusplus::message_t& eMsg, 791fc903b3dSAndrew Geissler crow::Response& res) 792fc903b3dSAndrew Geissler { 793fc903b3dSAndrew Geissler if (eMsg.get_error() == nullptr) 794fc903b3dSAndrew Geissler { 795*62598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error: {}", ec); 796fc903b3dSAndrew Geissler messages::internalError(res); 797fc903b3dSAndrew Geissler return; 798fc903b3dSAndrew Geissler } 799fc903b3dSAndrew Geissler std::string_view errorMessage = eMsg.get_error()->name; 800fc903b3dSAndrew Geissler 801fc903b3dSAndrew Geissler // If operation failed due to BMC not being in Ready state, tell 802fc903b3dSAndrew Geissler // user to retry in a bit 803fc903b3dSAndrew Geissler if (errorMessage == 804fc903b3dSAndrew Geissler std::string_view("xyz.openbmc_project.State.Chassis.Error.BMCNotReady")) 805fc903b3dSAndrew Geissler { 806*62598e31SEd Tanous BMCWEB_LOG_DEBUG("BMC not ready, operation not allowed right now"); 807fc903b3dSAndrew Geissler messages::serviceTemporarilyUnavailable(res, "10"); 808fc903b3dSAndrew Geissler return; 809fc903b3dSAndrew Geissler } 810fc903b3dSAndrew Geissler 811*62598e31SEd Tanous BMCWEB_LOG_ERROR("Chassis Power Cycle fail {} sdbusplus:{}", ec, 812*62598e31SEd Tanous errorMessage); 813fc903b3dSAndrew Geissler messages::internalError(res); 814fc903b3dSAndrew Geissler } 815fc903b3dSAndrew Geissler 8168d1b46d7Szhanghch05 inline void 8178d1b46d7Szhanghch05 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 818dd99e04bSP.K. Lee { 8197a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 820c3b3c92aSVijay Khemka "xyz.openbmc_project.State.Chassis"}; 821c3b3c92aSVijay Khemka 822c3b3c92aSVijay Khemka // Use mapper to get subtree paths. 8237a1dbc48SGeorge Liu dbus::utility::getSubTreePaths( 8247a1dbc48SGeorge Liu "/", 0, interfaces, 825b9d36b47SEd Tanous [asyncResp]( 8267a1dbc48SGeorge Liu const boost::system::error_code& ec, 827b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 828c3b3c92aSVijay Khemka if (ec) 829c3b3c92aSVijay Khemka { 830*62598e31SEd Tanous BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec); 831c3b3c92aSVijay Khemka messages::internalError(asyncResp->res); 832c3b3c92aSVijay Khemka return; 833c3b3c92aSVijay Khemka } 834c3b3c92aSVijay Khemka 835dd99e04bSP.K. Lee const char* processName = "xyz.openbmc_project.State.Chassis"; 836dd99e04bSP.K. Lee const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 837dd99e04bSP.K. Lee const char* destProperty = "RequestedPowerTransition"; 838dd99e04bSP.K. Lee const std::string propertyValue = 839dd99e04bSP.K. Lee "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 840002d39b4SEd Tanous std::string objectPath = "/xyz/openbmc_project/state/chassis_system0"; 841c3b3c92aSVijay Khemka 842c3b3c92aSVijay Khemka /* Look for system reset chassis path */ 843002d39b4SEd Tanous if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) == 844002d39b4SEd Tanous chassisList.end()) 845c3b3c92aSVijay Khemka { 846c3b3c92aSVijay Khemka /* We prefer to reset the full chassis_system, but if it doesn't 847c3b3c92aSVijay Khemka * exist on some platforms, fall back to a host-only power reset 848c3b3c92aSVijay Khemka */ 849c3b3c92aSVijay Khemka objectPath = "/xyz/openbmc_project/state/chassis0"; 850c3b3c92aSVijay Khemka } 851dd99e04bSP.K. Lee 8529ae226faSGeorge Liu sdbusplus::asio::setProperty( 8539ae226faSGeorge Liu *crow::connections::systemBus, processName, objectPath, 8549ae226faSGeorge Liu interfaceName, destProperty, propertyValue, 855fc903b3dSAndrew Geissler [asyncResp](const boost::system::error_code& ec2, 856fc903b3dSAndrew Geissler sdbusplus::message_t& sdbusErrMsg) { 857dd99e04bSP.K. Lee // Use "Set" method to set the property value. 8588a592810SEd Tanous if (ec2) 859dd99e04bSP.K. Lee { 860fc903b3dSAndrew Geissler handleChassisPowerCycleError(ec2, sdbusErrMsg, asyncResp->res); 861fc903b3dSAndrew Geissler 862dd99e04bSP.K. Lee return; 863dd99e04bSP.K. Lee } 864dd99e04bSP.K. Lee 865dd99e04bSP.K. Lee messages::success(asyncResp->res); 8669ae226faSGeorge Liu }); 8677a1dbc48SGeorge Liu }); 868dd99e04bSP.K. Lee } 869dd99e04bSP.K. Lee 870cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost( 871cf7eba09SNan Zhou App& app, const crow::Request& req, 8727e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 873cf7eba09SNan Zhou const std::string& /*chassisId*/) 874cf7eba09SNan Zhou { 8753ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 87645ca1b86SEd Tanous { 87745ca1b86SEd Tanous return; 87845ca1b86SEd Tanous } 879*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Chassis Reset."); 880dd99e04bSP.K. Lee 881dd99e04bSP.K. Lee std::string resetType; 882dd99e04bSP.K. Lee 883cf7eba09SNan Zhou if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 884dd99e04bSP.K. Lee { 885dd99e04bSP.K. Lee return; 886dd99e04bSP.K. Lee } 887dd99e04bSP.K. Lee 888dd99e04bSP.K. Lee if (resetType != "PowerCycle") 889dd99e04bSP.K. Lee { 890*62598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 891002d39b4SEd Tanous messages::actionParameterNotSupported(asyncResp->res, resetType, 892002d39b4SEd Tanous "ResetType"); 893dd99e04bSP.K. Lee 894dd99e04bSP.K. Lee return; 895dd99e04bSP.K. Lee } 896dd99e04bSP.K. Lee doChassisPowerCycle(asyncResp); 897dd99e04bSP.K. Lee } 8981cb1a9e6SAppaRao Puli 8991cb1a9e6SAppaRao Puli /** 900cf7eba09SNan Zhou * ChassisResetAction class supports the POST method for the Reset 901cf7eba09SNan Zhou * action. 902cf7eba09SNan Zhou * Function handles POST method request. 903cf7eba09SNan Zhou * Analyzes POST body before sending Reset request data to D-Bus. 9041cb1a9e6SAppaRao Puli */ 905cf7eba09SNan Zhou 906cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app) 9071cb1a9e6SAppaRao Puli { 908cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 909cf7eba09SNan Zhou .privileges(redfish::privileges::postChassis) 910cf7eba09SNan Zhou .methods(boost::beast::http::verb::post)( 911cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 912cf7eba09SNan Zhou } 913cf7eba09SNan Zhou 914cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet( 915cf7eba09SNan Zhou App& app, const crow::Request& req, 9167e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 917cf7eba09SNan Zhou const std::string& chassisId) 918cf7eba09SNan Zhou { 9193ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 9201cb1a9e6SAppaRao Puli { 92145ca1b86SEd Tanous return; 92245ca1b86SEd Tanous } 923cf7eba09SNan Zhou asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 924ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 925ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 9261476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 9271476687dSEd Tanous 9281476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 9295b9e95a1SNan Zhou nlohmann::json::array_t parameters; 9305b9e95a1SNan Zhou nlohmann::json::object_t parameter; 9315b9e95a1SNan Zhou parameter["Name"] = "ResetType"; 9325b9e95a1SNan Zhou parameter["Required"] = true; 9335b9e95a1SNan Zhou parameter["DataType"] = "String"; 9341476687dSEd Tanous nlohmann::json::array_t allowed; 935ad539545SPatrick Williams allowed.emplace_back("PowerCycle"); 9365b9e95a1SNan Zhou parameter["AllowableValues"] = std::move(allowed); 937ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 9385b9e95a1SNan Zhou 9391476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 940cf7eba09SNan Zhou } 941cf7eba09SNan Zhou 942cf7eba09SNan Zhou /** 943cf7eba09SNan Zhou * ChassisResetActionInfo derived class for delivering Chassis 944cf7eba09SNan Zhou * ResetType AllowableValues using ResetInfo schema. 945cf7eba09SNan Zhou */ 946cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app) 947cf7eba09SNan Zhou { 948cf7eba09SNan Zhou BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 949cf7eba09SNan Zhou .privileges(redfish::privileges::getActionInfo) 950cf7eba09SNan Zhou .methods(boost::beast::http::verb::get)( 951cf7eba09SNan Zhou std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 9521cb1a9e6SAppaRao Puli } 9531cb1a9e6SAppaRao Puli 954e37f8451SRapkiewicz, Pawel } // namespace redfish 955