xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision b4d593f1c6113311da4b29fc352187fbcb6d1fd4)
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"
257164bc62SChau Ly #include "redfish_util.hpp"
263ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
273ccb3adbSEd Tanous #include "utils/collection.hpp"
283ccb3adbSEd Tanous #include "utils/dbus_utils.hpp"
29cf7eba09SNan Zhou #include "utils/json_utils.hpp"
301abe55efSEd Tanous 
31e99073f5SGeorge Liu #include <boost/system/error_code.hpp>
32ef4c65b7SEd Tanous #include <boost/url/format.hpp>
331e1e598dSJonathan Doman #include <sdbusplus/asio/property.hpp>
34fc903b3dSAndrew Geissler #include <sdbusplus/message.hpp>
3586d89ed7SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp>
361214b7e7SGunnar Mills 
377a1dbc48SGeorge Liu #include <array>
383544d2a7SEd Tanous #include <ranges>
397a1dbc48SGeorge Liu #include <string_view>
407a1dbc48SGeorge Liu 
411abe55efSEd Tanous namespace redfish
421abe55efSEd Tanous {
43e37f8451SRapkiewicz, Pawel 
44e37f8451SRapkiewicz, Pawel /**
455e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
465e577bc1SWilly Tu  *
475e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
485e577bc1SWilly Tu  * calls
495e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
505e577bc1SWilly Tu  *
515e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
525e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
535e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
545e577bc1SWilly Tu  *
555e577bc1SWilly Tu  * @return None.
565e577bc1SWilly Tu  */
575e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
585e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
595e577bc1SWilly Tu {
605e577bc1SWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
615e577bc1SWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
625e577bc1SWilly Tu         (path / "storage").str, "xyz.openbmc_project.Association", "endpoints",
63d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
645e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
655e577bc1SWilly Tu         if (ec)
665e577bc1SWilly Tu         {
6762598e31SEd Tanous             BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error");
685e577bc1SWilly Tu             return;
695e577bc1SWilly Tu         }
705e577bc1SWilly Tu 
715e577bc1SWilly Tu         nlohmann::json::array_t storages;
725e577bc1SWilly Tu         for (const std::string& storagePath : storageList)
735e577bc1SWilly Tu         {
745e577bc1SWilly Tu             std::string id =
755e577bc1SWilly Tu                 sdbusplus::message::object_path(storagePath).filename();
765e577bc1SWilly Tu             if (id.empty())
775e577bc1SWilly Tu             {
785e577bc1SWilly Tu                 continue;
795e577bc1SWilly Tu             }
805e577bc1SWilly Tu 
815e577bc1SWilly Tu             nlohmann::json::object_t storage;
825e577bc1SWilly Tu             storage["@odata.id"] = boost::urls::format(
835e577bc1SWilly Tu                 "/redfish/v1/Systems/system/Storage/{}", id);
845e577bc1SWilly Tu             storages.emplace_back(std::move(storage));
855e577bc1SWilly Tu         }
865e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
875e577bc1SWilly Tu             storages.size();
885e577bc1SWilly Tu         asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
895e577bc1SWilly Tu     });
905e577bc1SWilly Tu }
915e577bc1SWilly Tu 
925e577bc1SWilly Tu /**
93beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
94beeca0aeSGunnar Mills  *
95ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
96beeca0aeSGunnar Mills  *
97beeca0aeSGunnar Mills  * @return None.
98beeca0aeSGunnar Mills  */
99ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
100beeca0aeSGunnar Mills {
1011e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
1021e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1031e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1041e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1051e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
106ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1071e1e598dSJonathan Doman                                           const std::string& chassisState) {
108beeca0aeSGunnar Mills         if (ec)
109beeca0aeSGunnar Mills         {
110a6e5e0abSCarson Labrado             if (ec == boost::system::errc::host_unreachable)
111a6e5e0abSCarson Labrado             {
112a6e5e0abSCarson Labrado                 // Service not available, no error, just don't return
113a6e5e0abSCarson Labrado                 // chassis state info
11462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("Service not available {}", ec);
115a6e5e0abSCarson Labrado                 return;
116a6e5e0abSCarson Labrado             }
11762598e31SEd Tanous             BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
118ac106bf6SEd Tanous             messages::internalError(asyncResp->res);
119beeca0aeSGunnar Mills             return;
120beeca0aeSGunnar Mills         }
121beeca0aeSGunnar Mills 
12262598e31SEd Tanous         BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
123beeca0aeSGunnar Mills         // Verify Chassis State
124002d39b4SEd Tanous         if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
125beeca0aeSGunnar Mills         {
126ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "On";
127ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
128beeca0aeSGunnar Mills         }
1291e1e598dSJonathan Doman         else if (chassisState ==
130beeca0aeSGunnar Mills                  "xyz.openbmc_project.State.Chassis.PowerState.Off")
131beeca0aeSGunnar Mills         {
132ac106bf6SEd Tanous             asyncResp->res.jsonValue["PowerState"] = "Off";
133ac106bf6SEd Tanous             asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
134beeca0aeSGunnar Mills         }
1351e1e598dSJonathan Doman     });
136beeca0aeSGunnar Mills }
137beeca0aeSGunnar Mills 
138c181942fSQiang XU /**
139c181942fSQiang XU  * Retrieves physical security properties over dbus
140c181942fSQiang XU  */
1417164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1427164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
143e99073f5SGeorge Liu     const boost::system::error_code& ec,
1447164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1457164bc62SChau Ly {
146c181942fSQiang XU     if (ec)
147c181942fSQiang XU     {
1484e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
149c181942fSQiang XU         //     mandatory property
15062598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
151c181942fSQiang XU         return;
152c181942fSQiang XU     }
153c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
154c181942fSQiang XU     for (const auto& object : subtree)
155c181942fSQiang XU     {
156840a9ffcSPatrick Williams         if (!object.second.empty())
157c181942fSQiang XU         {
158840a9ffcSPatrick Williams             const auto service = object.second.front();
1597164bc62SChau Ly 
1607164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
1617164bc62SChau Ly 
1627164bc62SChau Ly             sdbusplus::asio::getProperty<std::string>(
1637164bc62SChau Ly                 *crow::connections::systemBus, service.first, object.first,
1647164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
1657164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
1667164bc62SChau Ly                             const std::string& value) {
1677164bc62SChau Ly                 if (ec1)
1687164bc62SChau Ly                 {
1697164bc62SChau Ly                     // do not add err msg in redfish response, because this is
1707164bc62SChau Ly                     // not
1717164bc62SChau Ly                     //     mandatory property
1727164bc62SChau Ly                     BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
1737164bc62SChau Ly                     return;
1747164bc62SChau Ly                 }
1757164bc62SChau Ly                 asyncResp->res
1767164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
1777164bc62SChau Ly                 asyncResp->res
1787164bc62SChau Ly                     .jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
1797164bc62SChau Ly             });
1807164bc62SChau Ly 
181c181942fSQiang XU             return;
182c181942fSQiang XU         }
183c181942fSQiang XU     }
184c181942fSQiang XU }
185c181942fSQiang XU 
186cf7eba09SNan Zhou inline void handleChassisCollectionGet(
187cf7eba09SNan Zhou     App& app, const crow::Request& req,
188cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1891abe55efSEd Tanous {
1903ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
19145ca1b86SEd Tanous     {
19245ca1b86SEd Tanous         return;
19345ca1b86SEd Tanous     }
1948d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
1958d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
1968d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
1978d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
198e37f8451SRapkiewicz, Pawel 
1997a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
2007a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
2017a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
20202f6ff19SGunnar Mills     collection_util::getCollectionMembers(
20336b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
20436b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
205cf7eba09SNan Zhou }
206cf7eba09SNan Zhou 
207a5617496SJie Yang inline void getChassisContainedBy(
208a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
209a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
210a5617496SJie Yang     const dbus::utility::MapperEndPoints& upstreamChassisPaths)
211a5617496SJie Yang {
212a5617496SJie Yang     if (ec)
213a5617496SJie Yang     {
214a5617496SJie Yang         if (ec.value() != EBADR)
215a5617496SJie Yang         {
21662598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
217a5617496SJie Yang             messages::internalError(asyncResp->res);
218a5617496SJie Yang         }
219a5617496SJie Yang         return;
220a5617496SJie Yang     }
221a5617496SJie Yang     if (upstreamChassisPaths.empty())
222a5617496SJie Yang     {
223a5617496SJie Yang         return;
224a5617496SJie Yang     }
225a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
226a5617496SJie Yang     {
2278ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
228a5617496SJie Yang         messages::internalError(asyncResp->res);
229a5617496SJie Yang         return;
230a5617496SJie Yang     }
231a5617496SJie Yang 
232a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
233a5617496SJie Yang         upstreamChassisPaths[0]);
234a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
235a5617496SJie Yang     if (upstreamChassis.empty())
236a5617496SJie Yang     {
23762598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
23862598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
239a5617496SJie Yang         return;
240a5617496SJie Yang     }
241a5617496SJie Yang 
242a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
243a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
244a5617496SJie Yang }
245a5617496SJie Yang 
246a5617496SJie Yang inline void getChassisContains(
247a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
248a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
249a5617496SJie Yang     const dbus::utility::MapperEndPoints& downstreamChassisPaths)
250a5617496SJie Yang {
251a5617496SJie Yang     if (ec)
252a5617496SJie Yang     {
253a5617496SJie Yang         if (ec.value() != EBADR)
254a5617496SJie Yang         {
25562598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
256a5617496SJie Yang             messages::internalError(asyncResp->res);
257a5617496SJie Yang         }
258a5617496SJie Yang         return;
259a5617496SJie Yang     }
260a5617496SJie Yang     if (downstreamChassisPaths.empty())
261a5617496SJie Yang     {
262a5617496SJie Yang         return;
263a5617496SJie Yang     }
264a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
265a5617496SJie Yang     if (!jValue.is_array())
266a5617496SJie Yang     {
267a5617496SJie Yang         // Create the array if it was empty
268a5617496SJie Yang         jValue = nlohmann::json::array();
269a5617496SJie Yang     }
270a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
271a5617496SJie Yang     {
272a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
273a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
274a5617496SJie Yang         if (downstreamChassis.empty())
275a5617496SJie Yang         {
27662598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
27762598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
278a5617496SJie Yang             continue;
279a5617496SJie Yang         }
280a5617496SJie Yang         nlohmann::json link;
281a5617496SJie Yang         link["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}",
282a5617496SJie Yang                                                 downstreamChassis);
283a5617496SJie Yang         jValue.push_back(std::move(link));
284a5617496SJie Yang     }
285a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
286a5617496SJie Yang }
287a5617496SJie Yang 
288a5617496SJie Yang inline void
289a5617496SJie Yang     getChassisConnectivity(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
290a5617496SJie Yang                            const std::string& chassisId,
291a5617496SJie Yang                            const std::string& chassisPath)
292a5617496SJie Yang {
29362598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
294a5617496SJie Yang 
295a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
296a5617496SJie Yang         chassisPath + "/contained_by",
297a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
298a5617496SJie Yang 
299a5617496SJie Yang     dbus::utility::getAssociationEndPoints(
300a5617496SJie Yang         chassisPath + "/containing",
301a5617496SJie Yang         std::bind_front(getChassisContains, asyncResp, chassisId));
302a5617496SJie Yang }
303a5617496SJie Yang 
304cf7eba09SNan Zhou /**
305cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
306cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
307cf7eba09SNan Zhou  */
308cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
309cf7eba09SNan Zhou {
310cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
311cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
312cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
313cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
31462d5e2e4SEd Tanous }
315e37f8451SRapkiewicz, Pawel 
316308f70c7SWilly Tu inline void
317308f70c7SWilly Tu     getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
318308f70c7SWilly Tu                            const std::string& connectionName,
319308f70c7SWilly Tu                            const std::string& path)
320308f70c7SWilly Tu {
3211e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3221e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3231e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3245e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3251e1e598dSJonathan Doman                     const std::string& property) {
326308f70c7SWilly Tu         if (ec)
327308f70c7SWilly Tu         {
32862598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for Location");
329308f70c7SWilly Tu             messages::internalError(asyncResp->res);
330308f70c7SWilly Tu             return;
331308f70c7SWilly Tu         }
332308f70c7SWilly Tu 
333002d39b4SEd Tanous         asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3341e1e598dSJonathan Doman             property;
3351e1e598dSJonathan Doman     });
336308f70c7SWilly Tu }
337308f70c7SWilly Tu 
338308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
339308f70c7SWilly Tu                            const std::string& connectionName,
340308f70c7SWilly Tu                            const std::string& path)
341308f70c7SWilly Tu {
3421e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3431e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3441e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
3455e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3461e1e598dSJonathan Doman                     const std::string& chassisUUID) {
347308f70c7SWilly Tu         if (ec)
348308f70c7SWilly Tu         {
34962598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error for UUID");
350308f70c7SWilly Tu             messages::internalError(asyncResp->res);
351308f70c7SWilly Tu             return;
352308f70c7SWilly Tu         }
3531e1e598dSJonathan Doman         asyncResp->res.jsonValue["UUID"] = chassisUUID;
3541e1e598dSJonathan Doman     });
355308f70c7SWilly Tu }
356308f70c7SWilly Tu 
3577164bc62SChau Ly inline void handleDecoratorAssetProperties(
35845ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3597164bc62SChau Ly     const std::string& chassisId, const std::string& path,
3607164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
361cf7eba09SNan Zhou {
3627164bc62SChau Ly     const std::string* partNumber = nullptr;
3637164bc62SChau Ly     const std::string* serialNumber = nullptr;
3647164bc62SChau Ly     const std::string* manufacturer = nullptr;
3657164bc62SChau Ly     const std::string* model = nullptr;
3667164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
3677164bc62SChau Ly 
3687164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
3697164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3707164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
3717164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
3727164bc62SChau Ly 
3737164bc62SChau Ly     if (!success)
37445ca1b86SEd Tanous     {
3757164bc62SChau Ly         messages::internalError(asyncResp->res);
37645ca1b86SEd Tanous         return;
37745ca1b86SEd Tanous     }
378734bfe90SGunnar Mills 
3797164bc62SChau Ly     if (partNumber != nullptr)
3807164bc62SChau Ly     {
3817164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3827164bc62SChau Ly     }
3837164bc62SChau Ly 
3847164bc62SChau Ly     if (serialNumber != nullptr)
3857164bc62SChau Ly     {
3867164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
3877164bc62SChau Ly     }
3887164bc62SChau Ly 
3897164bc62SChau Ly     if (manufacturer != nullptr)
3907164bc62SChau Ly     {
3917164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
3927164bc62SChau Ly     }
3937164bc62SChau Ly 
3947164bc62SChau Ly     if (model != nullptr)
3957164bc62SChau Ly     {
3967164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
3977164bc62SChau Ly     }
3987164bc62SChau Ly 
3997164bc62SChau Ly     // SparePartNumber is optional on D-Bus
4007164bc62SChau Ly     // so skip if it is empty
4017164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4027164bc62SChau Ly     {
4037164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4047164bc62SChau Ly     }
4057164bc62SChau Ly 
4067164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4077164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
4087164bc62SChau Ly #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
4097164bc62SChau Ly     asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4107164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4117164bc62SChau Ly     // Power object
4127164bc62SChau Ly     asyncResp->res.jsonValue["Power"]["@odata.id"] =
4137164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
4147164bc62SChau Ly #endif
4157164bc62SChau Ly #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
4167164bc62SChau Ly     asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4177164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4187164bc62SChau Ly                             chassisId);
4197164bc62SChau Ly     asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
4207164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", chassisId);
4217164bc62SChau Ly     asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4227164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4237164bc62SChau Ly                             chassisId);
4247164bc62SChau Ly #endif
4257164bc62SChau Ly     // SensorCollection
4267164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4277164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
4287164bc62SChau Ly     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
4297164bc62SChau Ly 
4307164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4317164bc62SChau Ly     nlohmann::json::object_t system;
4327164bc62SChau Ly     system["@odata.id"] = "/redfish/v1/Systems/system";
4337164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4347164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4357164bc62SChau Ly         std::move(computerSystems);
4367164bc62SChau Ly 
4377164bc62SChau Ly     nlohmann::json::array_t managedBy;
4387164bc62SChau Ly     nlohmann::json::object_t manager;
4397164bc62SChau Ly     manager["@odata.id"] = "/redfish/v1/Managers/bmc";
4407164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4417164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4427164bc62SChau Ly     getChassisState(asyncResp);
4437164bc62SChau Ly     getStorageLink(asyncResp, path);
4447164bc62SChau Ly }
4457164bc62SChau Ly 
4467164bc62SChau Ly inline void handleChassisGetSubTree(
4477164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4487164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4497164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4507164bc62SChau Ly {
45162d5e2e4SEd Tanous     if (ec)
4521abe55efSEd Tanous     {
45362598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
454f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
455daf36e2eSEd Tanous         return;
456daf36e2eSEd Tanous     }
457daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
458cf7eba09SNan Zhou     for (const std::pair<
459cf7eba09SNan Zhou              std::string,
460cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4611214b7e7SGunnar Mills              object : subtree)
4621abe55efSEd Tanous     {
463daf36e2eSEd Tanous         const std::string& path = object.first;
464cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4651214b7e7SGunnar Mills             connectionNames = object.second;
4667e860f15SJohn Edward Broadbent 
467997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
468997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4691abe55efSEd Tanous         {
470daf36e2eSEd Tanous             continue;
471daf36e2eSEd Tanous         }
47226f03899SShawn McCarney 
473a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
474a5617496SJie Yang 
475002d39b4SEd Tanous         auto health = std::make_shared<HealthPopulate>(asyncResp);
476b49ac873SJames Feist 
47713451e39SWilly Tu         if constexpr (bmcwebEnableHealthPopulate)
47813451e39SWilly Tu         {
4796c3e9451SGeorge Liu             dbus::utility::getAssociationEndPoints(
4806c3e9451SGeorge Liu                 path + "/all_sensors",
4815e7e2dc5SEd Tanous                 [health](const boost::system::error_code& ec2,
4826c3e9451SGeorge Liu                          const dbus::utility::MapperEndPoints& resp) {
48323a21a1cSEd Tanous                 if (ec2)
484b49ac873SJames Feist                 {
485b49ac873SJames Feist                     return; // no sensors = no failures
486b49ac873SJames Feist                 }
4871e1e598dSJonathan Doman                 health->inventory = resp;
4881e1e598dSJonathan Doman             });
489b49ac873SJames Feist 
490b49ac873SJames Feist             health->populate();
49113451e39SWilly Tu         }
492b49ac873SJames Feist 
49326f6976fSEd Tanous         if (connectionNames.empty())
4941abe55efSEd Tanous         {
49562598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
496e0d918bcSEd Tanous             continue;
497daf36e2eSEd Tanous         }
498e0d918bcSEd Tanous 
4997164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
50049c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
501ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
50249c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
50349c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["ChassisType"] = "RackMount";
504cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
5057164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5067164bc62SChau Ly                                 chassisId);
5071476687dSEd Tanous         asyncResp->res
508cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
509ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
510ef4c65b7SEd Tanous                                 chassisId);
5111476687dSEd Tanous         asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
512ef4c65b7SEd Tanous             "/redfish/v1/Systems/system/PCIeDevices";
51349c53ac9SJohnathan Mantey 
5146c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
5156c3e9451SGeorge Liu             path + "/drive",
5167164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5176c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
51892903bd4SJohn Edward Broadbent             if (ec3 || resp.empty())
51992903bd4SJohn Edward Broadbent             {
52092903bd4SJohn Edward Broadbent                 return; // no drives = no failures
52192903bd4SJohn Edward Broadbent             }
52292903bd4SJohn Edward Broadbent 
52392903bd4SJohn Edward Broadbent             nlohmann::json reference;
5247164bc62SChau Ly             reference["@odata.id"] =
5257164bc62SChau Ly                 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
52692903bd4SJohn Edward Broadbent             asyncResp->res.jsonValue["Drives"] = std::move(reference);
52792903bd4SJohn Edward Broadbent         });
52892903bd4SJohn Edward Broadbent 
529002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
5301c8fba97SJames Feist 
5317164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
5321c8fba97SJames Feist         const std::array<const char*, 2> hasIndicatorLed = {
5331c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5340fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5351c8fba97SJames Feist 
536476b9cc5STejas Patil         const std::string assetTagInterface =
5370fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
538523d4868SLogananth Sundararaj         const std::string replaceableInterface =
539523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
540*b4d593f1SCarson Labrado         const std::string revisionInterface =
541*b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
542523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
543523d4868SLogananth Sundararaj         {
544523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
545476b9cc5STejas Patil             {
5461e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
547002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
548002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5497164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5501e1e598dSJonathan Doman                                            const std::string& property) {
5518a592810SEd Tanous                     if (ec2)
552476b9cc5STejas Patil                     {
5537164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBus response error for AssetTag: {}",
5547164bc62SChau Ly                                          ec2);
555476b9cc5STejas Patil                         messages::internalError(asyncResp->res);
556476b9cc5STejas Patil                         return;
557476b9cc5STejas Patil                     }
558002d39b4SEd Tanous                     asyncResp->res.jsonValue["AssetTag"] = property;
5591e1e598dSJonathan Doman                 });
560476b9cc5STejas Patil             }
561523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
562523d4868SLogananth Sundararaj             {
563523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
564523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
565523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5667164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
567523d4868SLogananth Sundararaj                                            const bool property) {
568523d4868SLogananth Sundararaj                     if (ec2)
569523d4868SLogananth Sundararaj                     {
57062598e31SEd Tanous                         BMCWEB_LOG_ERROR(
5717164bc62SChau Ly                             "DBus response error for HotPluggable: {}", ec2);
572523d4868SLogananth Sundararaj                         messages::internalError(asyncResp->res);
573523d4868SLogananth Sundararaj                         return;
574523d4868SLogananth Sundararaj                     }
575523d4868SLogananth Sundararaj                     asyncResp->res.jsonValue["HotPluggable"] = property;
576523d4868SLogananth Sundararaj                 });
577523d4868SLogananth Sundararaj             }
578*b4d593f1SCarson Labrado             else if (interface == revisionInterface)
579*b4d593f1SCarson Labrado             {
580*b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
581*b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
582*b4d593f1SCarson Labrado                     revisionInterface, "Version",
583*b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
584*b4d593f1SCarson Labrado                                            const std::string& property) {
585*b4d593f1SCarson Labrado                     if (ec2)
586*b4d593f1SCarson Labrado                     {
587*b4d593f1SCarson Labrado                         BMCWEB_LOG_ERROR("DBus response error for Version: {}",
588*b4d593f1SCarson Labrado                                          ec2);
589*b4d593f1SCarson Labrado                         messages::internalError(asyncResp->res);
590*b4d593f1SCarson Labrado                         return;
591*b4d593f1SCarson Labrado                     }
592*b4d593f1SCarson Labrado                     asyncResp->res.jsonValue["Version"] = property;
593*b4d593f1SCarson Labrado                 });
594*b4d593f1SCarson Labrado             }
595523d4868SLogananth Sundararaj         }
596476b9cc5STejas Patil 
5971c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
5981c8fba97SJames Feist         {
5997164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
6001c8fba97SJames Feist             {
6011c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
60259a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
6031c8fba97SJames Feist                 break;
6041c8fba97SJames Feist             }
6051c8fba97SJames Feist         }
6061c8fba97SJames Feist 
60786d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
60886d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
60986d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6107164bc62SChau Ly             [asyncResp, chassisId,
6117164bc62SChau Ly              path](const boost::system::error_code&,
612cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6137164bc62SChau Ly             handleDecoratorAssetProperties(asyncResp, chassisId, path,
6147164bc62SChau Ly                                            propertiesList);
61586d89ed7SKrzysztof Grobelny         });
6162c37b4b0SSharad Yadav 
617308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6182c37b4b0SSharad Yadav         {
619308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6202c37b4b0SSharad Yadav             {
621308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6222c37b4b0SSharad Yadav             }
623cf7eba09SNan Zhou             else if (interface ==
6240fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6252c37b4b0SSharad Yadav             {
626002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6272c37b4b0SSharad Yadav             }
6282c37b4b0SSharad Yadav         }
6292c37b4b0SSharad Yadav 
630daf36e2eSEd Tanous         return;
631daf36e2eSEd Tanous     }
632e0d918bcSEd Tanous 
633daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
634d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6357164bc62SChau Ly }
636c181942fSQiang XU 
6377164bc62SChau Ly inline void
6387164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6397164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6407164bc62SChau Ly                      const std::string& chassisId)
6417164bc62SChau Ly {
6427164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6437164bc62SChau Ly     {
6447164bc62SChau Ly         return;
6457164bc62SChau Ly     }
6467164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6477164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6487164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6497164bc62SChau Ly 
6507164bc62SChau Ly     dbus::utility::getSubTree(
6517164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6527164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6537164bc62SChau Ly 
6547164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6557164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6567164bc62SChau Ly 
6577164bc62SChau Ly     dbus::utility::getSubTree(
6587164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6597164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
660cf7eba09SNan Zhou }
6611c8fba97SJames Feist 
662cf7eba09SNan Zhou inline void
663cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6647e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
665cf7eba09SNan Zhou                        const std::string& param)
666cf7eba09SNan Zhou {
6673ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
66845ca1b86SEd Tanous     {
66945ca1b86SEd Tanous         return;
67045ca1b86SEd Tanous     }
6719f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6721c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6731c8fba97SJames Feist 
6747e860f15SJohn Edward Broadbent     if (param.empty())
6751c8fba97SJames Feist     {
6761c8fba97SJames Feist         return;
6771c8fba97SJames Feist     }
6781c8fba97SJames Feist 
67915ed6780SWilly Tu     if (!json_util::readJsonPatch(
6807e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6817e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6821c8fba97SJames Feist     {
6831c8fba97SJames Feist         return;
6841c8fba97SJames Feist     }
6851c8fba97SJames Feist 
6869f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6879f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6881c8fba97SJames Feist     {
6891c8fba97SJames Feist         return; // delete this when we support more patch properties
6901c8fba97SJames Feist     }
691d6aa0093SGunnar Mills     if (indicatorLed)
692d6aa0093SGunnar Mills     {
6937e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6947e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6950fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
696d6aa0093SGunnar Mills     }
6971c8fba97SJames Feist 
698e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
6991c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
7001c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
7011c8fba97SJames Feist 
7027e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7031c8fba97SJames Feist 
704e99073f5SGeorge Liu     dbus::utility::getSubTree(
705e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
706cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7075e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
708b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7091c8fba97SJames Feist         if (ec)
7101c8fba97SJames Feist         {
71162598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7121c8fba97SJames Feist             messages::internalError(asyncResp->res);
7131c8fba97SJames Feist             return;
7141c8fba97SJames Feist         }
7151c8fba97SJames Feist 
7161c8fba97SJames Feist         // Iterate over all retrieved ObjectPaths.
717cf7eba09SNan Zhou         for (const std::pair<
718cf7eba09SNan Zhou                  std::string,
719cf7eba09SNan Zhou                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
7201214b7e7SGunnar Mills                  object : subtree)
7211c8fba97SJames Feist         {
7221c8fba97SJames Feist             const std::string& path = object.first;
723cf7eba09SNan Zhou             const std::vector<std::pair<std::string, std::vector<std::string>>>&
7241214b7e7SGunnar Mills                 connectionNames = object.second;
7251c8fba97SJames Feist 
726997093ebSGeorge Liu             sdbusplus::message::object_path objPath(path);
727997093ebSGeorge Liu             if (objPath.filename() != chassisId)
7281c8fba97SJames Feist             {
7291c8fba97SJames Feist                 continue;
7301c8fba97SJames Feist             }
7311c8fba97SJames Feist 
73226f6976fSEd Tanous             if (connectionNames.empty())
7331c8fba97SJames Feist             {
73462598e31SEd Tanous                 BMCWEB_LOG_ERROR("Got 0 Connection names");
7351c8fba97SJames Feist                 continue;
7361c8fba97SJames Feist             }
7371c8fba97SJames Feist 
73823a21a1cSEd Tanous             const std::vector<std::string>& interfaces3 =
7391c8fba97SJames Feist                 connectionNames[0].second;
7401c8fba97SJames Feist 
7411c8fba97SJames Feist             const std::array<const char*, 2> hasIndicatorLed = {
7421c8fba97SJames Feist                 "xyz.openbmc_project.Inventory.Item.Panel",
7430fda0f12SGeorge Liu                 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7441c8fba97SJames Feist             bool indicatorChassis = false;
7451c8fba97SJames Feist             for (const char* interface : hasIndicatorLed)
7461c8fba97SJames Feist             {
7473544d2a7SEd Tanous                 if (std::ranges::find(interfaces3, interface) !=
7483544d2a7SEd Tanous                     interfaces3.end())
7491c8fba97SJames Feist                 {
7501c8fba97SJames Feist                     indicatorChassis = true;
7511c8fba97SJames Feist                     break;
7521c8fba97SJames Feist                 }
7531c8fba97SJames Feist             }
7549f8bfa7cSGunnar Mills             if (locationIndicatorActive)
7559f8bfa7cSGunnar Mills             {
7569f8bfa7cSGunnar Mills                 if (indicatorChassis)
7579f8bfa7cSGunnar Mills                 {
75859a17e4fSGeorge Liu                     setSystemLocationIndicatorActive(asyncResp,
759002d39b4SEd Tanous                                                      *locationIndicatorActive);
7609f8bfa7cSGunnar Mills                 }
7619f8bfa7cSGunnar Mills                 else
7629f8bfa7cSGunnar Mills                 {
763002d39b4SEd Tanous                     messages::propertyUnknown(asyncResp->res,
764002d39b4SEd Tanous                                               "LocationIndicatorActive");
7659f8bfa7cSGunnar Mills                 }
7669f8bfa7cSGunnar Mills             }
7679f8bfa7cSGunnar Mills             if (indicatorLed)
7689f8bfa7cSGunnar Mills             {
7691c8fba97SJames Feist                 if (indicatorChassis)
7701c8fba97SJames Feist                 {
771f23b7296SEd Tanous                     setIndicatorLedState(asyncResp, *indicatorLed);
7721c8fba97SJames Feist                 }
7731c8fba97SJames Feist                 else
7741c8fba97SJames Feist                 {
775cf7eba09SNan Zhou                     messages::propertyUnknown(asyncResp->res, "IndicatorLED");
7761c8fba97SJames Feist                 }
7771c8fba97SJames Feist             }
7781c8fba97SJames Feist             return;
7791c8fba97SJames Feist         }
7801c8fba97SJames Feist 
781d8a5d5d8SJiaqing Zhao         messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
782e99073f5SGeorge Liu     });
783cf7eba09SNan Zhou }
784cf7eba09SNan Zhou 
785cf7eba09SNan Zhou /**
786cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
787cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
788cf7eba09SNan Zhou  */
789cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
790cf7eba09SNan Zhou {
791cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
792cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
793cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
794cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
795cf7eba09SNan Zhou 
796cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
797cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
798cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
799cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8001c8fba97SJames Feist }
801dd99e04bSP.K. Lee 
802fc903b3dSAndrew Geissler /**
803fc903b3dSAndrew Geissler  * Handle error responses from d-bus for chassis power cycles
804fc903b3dSAndrew Geissler  */
805fc903b3dSAndrew Geissler inline void handleChassisPowerCycleError(const boost::system::error_code& ec,
806fc903b3dSAndrew Geissler                                          const sdbusplus::message_t& eMsg,
807fc903b3dSAndrew Geissler                                          crow::Response& res)
808fc903b3dSAndrew Geissler {
809fc903b3dSAndrew Geissler     if (eMsg.get_error() == nullptr)
810fc903b3dSAndrew Geissler     {
81162598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error: {}", ec);
812fc903b3dSAndrew Geissler         messages::internalError(res);
813fc903b3dSAndrew Geissler         return;
814fc903b3dSAndrew Geissler     }
815fc903b3dSAndrew Geissler     std::string_view errorMessage = eMsg.get_error()->name;
816fc903b3dSAndrew Geissler 
817fc903b3dSAndrew Geissler     // If operation failed due to BMC not being in Ready state, tell
818fc903b3dSAndrew Geissler     // user to retry in a bit
819fc903b3dSAndrew Geissler     if (errorMessage ==
820fc903b3dSAndrew Geissler         std::string_view("xyz.openbmc_project.State.Chassis.Error.BMCNotReady"))
821fc903b3dSAndrew Geissler     {
82262598e31SEd Tanous         BMCWEB_LOG_DEBUG("BMC not ready, operation not allowed right now");
823fc903b3dSAndrew Geissler         messages::serviceTemporarilyUnavailable(res, "10");
824fc903b3dSAndrew Geissler         return;
825fc903b3dSAndrew Geissler     }
826fc903b3dSAndrew Geissler 
82762598e31SEd Tanous     BMCWEB_LOG_ERROR("Chassis Power Cycle fail {} sdbusplus:{}", ec,
82862598e31SEd Tanous                      errorMessage);
829fc903b3dSAndrew Geissler     messages::internalError(res);
830fc903b3dSAndrew Geissler }
831fc903b3dSAndrew Geissler 
8328d1b46d7Szhanghch05 inline void
8338d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
834dd99e04bSP.K. Lee {
8357a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
836c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
837c3b3c92aSVijay Khemka 
838c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8397a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8407a1dbc48SGeorge Liu         "/", 0, interfaces,
841b9d36b47SEd Tanous         [asyncResp](
8427a1dbc48SGeorge Liu             const boost::system::error_code& ec,
843b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
844c3b3c92aSVijay Khemka         if (ec)
845c3b3c92aSVijay Khemka         {
84662598e31SEd Tanous             BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
847c3b3c92aSVijay Khemka             messages::internalError(asyncResp->res);
848c3b3c92aSVijay Khemka             return;
849c3b3c92aSVijay Khemka         }
850c3b3c92aSVijay Khemka 
851dd99e04bSP.K. Lee         const char* processName = "xyz.openbmc_project.State.Chassis";
852dd99e04bSP.K. Lee         const char* interfaceName = "xyz.openbmc_project.State.Chassis";
853dd99e04bSP.K. Lee         const char* destProperty = "RequestedPowerTransition";
854dd99e04bSP.K. Lee         const std::string propertyValue =
855dd99e04bSP.K. Lee             "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
856002d39b4SEd Tanous         std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
857c3b3c92aSVijay Khemka 
858c3b3c92aSVijay Khemka         /* Look for system reset chassis path */
8593544d2a7SEd Tanous         if ((std::ranges::find(chassisList, objectPath)) == chassisList.end())
860c3b3c92aSVijay Khemka         {
861c3b3c92aSVijay Khemka             /* We prefer to reset the full chassis_system, but if it doesn't
862c3b3c92aSVijay Khemka              * exist on some platforms, fall back to a host-only power reset
863c3b3c92aSVijay Khemka              */
864c3b3c92aSVijay Khemka             objectPath = "/xyz/openbmc_project/state/chassis0";
865c3b3c92aSVijay Khemka         }
866dd99e04bSP.K. Lee 
8679ae226faSGeorge Liu         sdbusplus::asio::setProperty(
8689ae226faSGeorge Liu             *crow::connections::systemBus, processName, objectPath,
8699ae226faSGeorge Liu             interfaceName, destProperty, propertyValue,
870fc903b3dSAndrew Geissler             [asyncResp](const boost::system::error_code& ec2,
871fc903b3dSAndrew Geissler                         sdbusplus::message_t& sdbusErrMsg) {
872dd99e04bSP.K. Lee             // Use "Set" method to set the property value.
8738a592810SEd Tanous             if (ec2)
874dd99e04bSP.K. Lee             {
875fc903b3dSAndrew Geissler                 handleChassisPowerCycleError(ec2, sdbusErrMsg, asyncResp->res);
876fc903b3dSAndrew Geissler 
877dd99e04bSP.K. Lee                 return;
878dd99e04bSP.K. Lee             }
879dd99e04bSP.K. Lee 
880dd99e04bSP.K. Lee             messages::success(asyncResp->res);
8819ae226faSGeorge Liu         });
8827a1dbc48SGeorge Liu     });
883dd99e04bSP.K. Lee }
884dd99e04bSP.K. Lee 
885cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
886cf7eba09SNan Zhou     App& app, const crow::Request& req,
8877e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
888cf7eba09SNan Zhou     const std::string& /*chassisId*/)
889cf7eba09SNan Zhou {
8903ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
89145ca1b86SEd Tanous     {
89245ca1b86SEd Tanous         return;
89345ca1b86SEd Tanous     }
89462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
895dd99e04bSP.K. Lee 
896dd99e04bSP.K. Lee     std::string resetType;
897dd99e04bSP.K. Lee 
898cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
899dd99e04bSP.K. Lee     {
900dd99e04bSP.K. Lee         return;
901dd99e04bSP.K. Lee     }
902dd99e04bSP.K. Lee 
903dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
904dd99e04bSP.K. Lee     {
90562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
906002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
907002d39b4SEd Tanous                                               "ResetType");
908dd99e04bSP.K. Lee 
909dd99e04bSP.K. Lee         return;
910dd99e04bSP.K. Lee     }
911dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
912dd99e04bSP.K. Lee }
9131cb1a9e6SAppaRao Puli 
9141cb1a9e6SAppaRao Puli /**
915cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
916cf7eba09SNan Zhou  * action.
917cf7eba09SNan Zhou  * Function handles POST method request.
918cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
9191cb1a9e6SAppaRao Puli  */
920cf7eba09SNan Zhou 
921cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
9221cb1a9e6SAppaRao Puli {
923cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
924cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
925cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
926cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
927cf7eba09SNan Zhou }
928cf7eba09SNan Zhou 
929cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
930cf7eba09SNan Zhou     App& app, const crow::Request& req,
9317e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
932cf7eba09SNan Zhou     const std::string& chassisId)
933cf7eba09SNan Zhou {
9343ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
9351cb1a9e6SAppaRao Puli     {
93645ca1b86SEd Tanous         return;
93745ca1b86SEd Tanous     }
938cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
939ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
940ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9411476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9421476687dSEd Tanous 
9431476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9445b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9455b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9465b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9475b9e95a1SNan Zhou     parameter["Required"] = true;
9485b9e95a1SNan Zhou     parameter["DataType"] = "String";
9491476687dSEd Tanous     nlohmann::json::array_t allowed;
950ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9515b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
952ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9535b9e95a1SNan Zhou 
9541476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
955cf7eba09SNan Zhou }
956cf7eba09SNan Zhou 
957cf7eba09SNan Zhou /**
958cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
959cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
960cf7eba09SNan Zhou  */
961cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
962cf7eba09SNan Zhou {
963cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
964cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
965cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
966cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9671cb1a9e6SAppaRao Puli }
9681cb1a9e6SAppaRao Puli 
969e37f8451SRapkiewicz, Pawel } // namespace redfish
970