xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision afc474aef028555fc0a6deb425bdad86f0a34db6)
1e37f8451SRapkiewicz, Pawel /*
26be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
36be832e2SEd Tanous 
46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
56be832e2SEd Tanous you may not use this file except in compliance with the License.
66be832e2SEd Tanous You may obtain a copy of the License at
76be832e2SEd Tanous 
86be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
96be832e2SEd Tanous 
106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136be832e2SEd Tanous See the License for the specific language governing permissions and
146be832e2SEd Tanous limitations under the License.
15e37f8451SRapkiewicz, Pawel */
16e37f8451SRapkiewicz, Pawel #pragma once
17e37f8451SRapkiewicz, Pawel 
183ccb3adbSEd Tanous #include "app.hpp"
197a1dbc48SGeorge Liu #include "dbus_utility.hpp"
20539d8c6bSEd Tanous #include "generated/enums/action_info.hpp"
21539d8c6bSEd Tanous #include "generated/enums/chassis.hpp"
22539d8c6bSEd Tanous #include "generated/enums/resource.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;
82253f11b8SEd Tanous                 storage["@odata.id"] =
83253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
84253f11b8SEd Tanous                                         BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
855e577bc1SWilly Tu                 storages.emplace_back(std::move(storage));
865e577bc1SWilly Tu             }
875e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
885e577bc1SWilly Tu                 storages.size();
895e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
905e577bc1SWilly Tu         });
915e577bc1SWilly Tu }
925e577bc1SWilly Tu 
935e577bc1SWilly Tu /**
94beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
95beeca0aeSGunnar Mills  *
96ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
97beeca0aeSGunnar Mills  *
98beeca0aeSGunnar Mills  * @return None.
99beeca0aeSGunnar Mills  */
100ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
101beeca0aeSGunnar Mills {
1021e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
1031e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1041e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1051e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1061e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
107ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1081e1e598dSJonathan Doman                                           const std::string& chassisState) {
109beeca0aeSGunnar Mills             if (ec)
110beeca0aeSGunnar Mills             {
111a6e5e0abSCarson Labrado                 if (ec == boost::system::errc::host_unreachable)
112a6e5e0abSCarson Labrado                 {
113a6e5e0abSCarson Labrado                     // Service not available, no error, just don't return
114a6e5e0abSCarson Labrado                     // chassis state info
11562598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Service not available {}", ec);
116a6e5e0abSCarson Labrado                     return;
117a6e5e0abSCarson Labrado                 }
11862598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
119ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
120beeca0aeSGunnar Mills                 return;
121beeca0aeSGunnar Mills             }
122beeca0aeSGunnar Mills 
12362598e31SEd Tanous             BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
124beeca0aeSGunnar Mills             // Verify Chassis State
125bd79bce8SPatrick Williams             if (chassisState ==
126bd79bce8SPatrick Williams                 "xyz.openbmc_project.State.Chassis.PowerState.On")
127beeca0aeSGunnar Mills             {
128bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
129bd79bce8SPatrick Williams                     resource::PowerState::On;
130539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
131539d8c6bSEd Tanous                     resource::State::Enabled;
132beeca0aeSGunnar Mills             }
1331e1e598dSJonathan Doman             else if (chassisState ==
134beeca0aeSGunnar Mills                      "xyz.openbmc_project.State.Chassis.PowerState.Off")
135beeca0aeSGunnar Mills             {
136bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
137bd79bce8SPatrick Williams                     resource::PowerState::Off;
138539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
139539d8c6bSEd Tanous                     resource::State::StandbyOffline;
140beeca0aeSGunnar Mills             }
1411e1e598dSJonathan Doman         });
142beeca0aeSGunnar Mills }
143beeca0aeSGunnar Mills 
144c181942fSQiang XU /**
145c181942fSQiang XU  * Retrieves physical security properties over dbus
146c181942fSQiang XU  */
1477164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1487164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
149e99073f5SGeorge Liu     const boost::system::error_code& ec,
1507164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1517164bc62SChau Ly {
152c181942fSQiang XU     if (ec)
153c181942fSQiang XU     {
1544e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
155c181942fSQiang XU         //     mandatory property
15662598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
157c181942fSQiang XU         return;
158c181942fSQiang XU     }
159c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
160c181942fSQiang XU     for (const auto& object : subtree)
161c181942fSQiang XU     {
162840a9ffcSPatrick Williams         if (!object.second.empty())
163c181942fSQiang XU         {
16489144a3aSEd Tanous             const auto& service = object.second.front();
1657164bc62SChau Ly 
1667164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
1677164bc62SChau Ly 
1687164bc62SChau Ly             sdbusplus::asio::getProperty<std::string>(
1697164bc62SChau Ly                 *crow::connections::systemBus, service.first, object.first,
1707164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
1717164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
1727164bc62SChau Ly                             const std::string& value) {
1737164bc62SChau Ly                     if (ec1)
1747164bc62SChau Ly                     {
175bd79bce8SPatrick Williams                         // do not add err msg in redfish response, because this
176bd79bce8SPatrick Williams                         // is not
1777164bc62SChau Ly                         //     mandatory property
1787164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
1797164bc62SChau Ly                         return;
1807164bc62SChau Ly                     }
181bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["PhysicalSecurity"]
182bd79bce8SPatrick Williams                                             ["IntrusionSensorNumber"] = 1;
1837164bc62SChau Ly                     asyncResp->res
184bd79bce8SPatrick Williams                         .jsonValue["PhysicalSecurity"]["IntrusionSensor"] =
185bd79bce8SPatrick Williams                         value;
1867164bc62SChau Ly                 });
1877164bc62SChau Ly 
188c181942fSQiang XU             return;
189c181942fSQiang XU         }
190c181942fSQiang XU     }
191c181942fSQiang XU }
192c181942fSQiang XU 
193cf7eba09SNan Zhou inline void handleChassisCollectionGet(
194cf7eba09SNan Zhou     App& app, const crow::Request& req,
195cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1961abe55efSEd Tanous {
1973ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
19845ca1b86SEd Tanous     {
19945ca1b86SEd Tanous         return;
20045ca1b86SEd Tanous     }
2018d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
2028d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
2038d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
2048d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
205e37f8451SRapkiewicz, Pawel 
2067a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
2077a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
2087a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
20902f6ff19SGunnar Mills     collection_util::getCollectionMembers(
21036b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
21136b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
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,
21728ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths)
218a5617496SJie Yang {
219a5617496SJie Yang     if (ec)
220a5617496SJie Yang     {
221a5617496SJie Yang         if (ec.value() != EBADR)
222a5617496SJie Yang         {
22362598e31SEd 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     {
2348ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple 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     {
24462598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
24562598e31SEd 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,
25628ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths)
257a5617496SJie Yang {
258a5617496SJie Yang     if (ec)
259a5617496SJie Yang     {
260a5617496SJie Yang         if (ec.value() != EBADR)
261a5617496SJie Yang         {
26262598e31SEd 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         {
28362598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
28462598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
285a5617496SJie Yang             continue;
286a5617496SJie Yang         }
287a5617496SJie Yang         nlohmann::json link;
288bd79bce8SPatrick Williams         link["@odata.id"] =
289bd79bce8SPatrick Williams             boost::urls::format("/redfish/v1/Chassis/{}", 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 
295bd79bce8SPatrick Williams inline void getChassisConnectivity(
296bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
297bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& chassisPath)
298a5617496SJie Yang {
29962598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
300a5617496SJie Yang 
30128ee563eSMyung Bae     constexpr std::array<std::string_view, 2> interfaces{
30228ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Board",
30328ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Chassis"};
30428ee563eSMyung Bae 
30528ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
306a5617496SJie Yang         chassisPath + "/contained_by",
30728ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
30828ee563eSMyung Bae         interfaces,
309a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
310a5617496SJie Yang 
31128ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
312a5617496SJie Yang         chassisPath + "/containing",
31328ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
31428ee563eSMyung Bae         interfaces, std::bind_front(getChassisContains, asyncResp, chassisId));
315a5617496SJie Yang }
316a5617496SJie Yang 
317cf7eba09SNan Zhou /**
318cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
319cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
320cf7eba09SNan Zhou  */
321cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
322cf7eba09SNan Zhou {
323cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
324cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
325cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
326cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
32762d5e2e4SEd Tanous }
328e37f8451SRapkiewicz, Pawel 
329bd79bce8SPatrick Williams inline void getChassisLocationCode(
330bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
331bd79bce8SPatrick Williams     const std::string& connectionName, const std::string& path)
332308f70c7SWilly Tu {
3331e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3341e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3351e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3365e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3371e1e598dSJonathan Doman                     const std::string& property) {
338308f70c7SWilly Tu             if (ec)
339308f70c7SWilly Tu             {
34062598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Location");
341308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
342308f70c7SWilly Tu                 return;
343308f70c7SWilly Tu             }
344308f70c7SWilly Tu 
345bd79bce8SPatrick Williams             asyncResp->res
346bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3471e1e598dSJonathan Doman                 property;
3481e1e598dSJonathan Doman         });
349308f70c7SWilly Tu }
350308f70c7SWilly Tu 
351308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
352308f70c7SWilly Tu                            const std::string& connectionName,
353308f70c7SWilly Tu                            const std::string& path)
354308f70c7SWilly Tu {
3551e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3561e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3571e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
3585e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3591e1e598dSJonathan Doman                     const std::string& chassisUUID) {
360308f70c7SWilly Tu             if (ec)
361308f70c7SWilly Tu             {
36262598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for UUID");
363308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
364308f70c7SWilly Tu                 return;
365308f70c7SWilly Tu             }
3661e1e598dSJonathan Doman             asyncResp->res.jsonValue["UUID"] = chassisUUID;
3671e1e598dSJonathan Doman         });
368308f70c7SWilly Tu }
369308f70c7SWilly Tu 
3707164bc62SChau Ly inline void handleDecoratorAssetProperties(
37145ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3727164bc62SChau Ly     const std::string& chassisId, const std::string& path,
3737164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
374cf7eba09SNan Zhou {
3757164bc62SChau Ly     const std::string* partNumber = nullptr;
3767164bc62SChau Ly     const std::string* serialNumber = nullptr;
3777164bc62SChau Ly     const std::string* manufacturer = nullptr;
3787164bc62SChau Ly     const std::string* model = nullptr;
3797164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
3807164bc62SChau Ly 
3817164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
3827164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
3837164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
3847164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
3857164bc62SChau Ly 
3867164bc62SChau Ly     if (!success)
38745ca1b86SEd Tanous     {
3887164bc62SChau Ly         messages::internalError(asyncResp->res);
38945ca1b86SEd Tanous         return;
39045ca1b86SEd Tanous     }
391734bfe90SGunnar Mills 
3927164bc62SChau Ly     if (partNumber != nullptr)
3937164bc62SChau Ly     {
3947164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
3957164bc62SChau Ly     }
3967164bc62SChau Ly 
3977164bc62SChau Ly     if (serialNumber != nullptr)
3987164bc62SChau Ly     {
3997164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
4007164bc62SChau Ly     }
4017164bc62SChau Ly 
4027164bc62SChau Ly     if (manufacturer != nullptr)
4037164bc62SChau Ly     {
4047164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
4057164bc62SChau Ly     }
4067164bc62SChau Ly 
4077164bc62SChau Ly     if (model != nullptr)
4087164bc62SChau Ly     {
4097164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
4107164bc62SChau Ly     }
4117164bc62SChau Ly 
4127164bc62SChau Ly     // SparePartNumber is optional on D-Bus
4137164bc62SChau Ly     // so skip if it is empty
4147164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4157164bc62SChau Ly     {
4167164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4177164bc62SChau Ly     }
4187164bc62SChau Ly 
4197164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4207164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
42125b54dbaSEd Tanous 
42225b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
42325b54dbaSEd Tanous     {
4247164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4257164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4267164bc62SChau Ly         // Power object
4277164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4287164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
42925b54dbaSEd Tanous     }
43025b54dbaSEd Tanous 
43125b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
43225b54dbaSEd Tanous     {
4337164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4347164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4357164bc62SChau Ly                                 chassisId);
4367164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
43725b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
43825b54dbaSEd Tanous                                 chassisId);
4397164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4407164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4417164bc62SChau Ly                                 chassisId);
44225b54dbaSEd Tanous     }
4437164bc62SChau Ly     // SensorCollection
4447164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4457164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
446539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
4477164bc62SChau Ly 
4487164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4497164bc62SChau Ly     nlohmann::json::object_t system;
450bd79bce8SPatrick Williams     system["@odata.id"] =
451bd79bce8SPatrick Williams         std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
4527164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
4537164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
4547164bc62SChau Ly         std::move(computerSystems);
4557164bc62SChau Ly 
4567164bc62SChau Ly     nlohmann::json::array_t managedBy;
4577164bc62SChau Ly     nlohmann::json::object_t manager;
458253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
459253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
4607164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
4617164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
4627164bc62SChau Ly     getChassisState(asyncResp);
4637164bc62SChau Ly     getStorageLink(asyncResp, path);
4647164bc62SChau Ly }
4657164bc62SChau Ly 
4667164bc62SChau Ly inline void handleChassisGetSubTree(
4677164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4687164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
4697164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
4707164bc62SChau Ly {
47162d5e2e4SEd Tanous     if (ec)
4721abe55efSEd Tanous     {
47362598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
474f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
475daf36e2eSEd Tanous         return;
476daf36e2eSEd Tanous     }
477daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
478cf7eba09SNan Zhou     for (const std::pair<
479cf7eba09SNan Zhou              std::string,
480cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
4811214b7e7SGunnar Mills              object : subtree)
4821abe55efSEd Tanous     {
483daf36e2eSEd Tanous         const std::string& path = object.first;
484cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
4851214b7e7SGunnar Mills             connectionNames = object.second;
4867e860f15SJohn Edward Broadbent 
487997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
488997093ebSGeorge Liu         if (objPath.filename() != chassisId)
4891abe55efSEd Tanous         {
490daf36e2eSEd Tanous             continue;
491daf36e2eSEd Tanous         }
49226f03899SShawn McCarney 
493a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
494a5617496SJie Yang 
49526f6976fSEd Tanous         if (connectionNames.empty())
4961abe55efSEd Tanous         {
49762598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
498e0d918bcSEd Tanous             continue;
499daf36e2eSEd Tanous         }
500e0d918bcSEd Tanous 
5017164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
50249c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
503ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
50449c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
505539d8c6bSEd Tanous         asyncResp->res.jsonValue["ChassisType"] =
506539d8c6bSEd Tanous             chassis::ChassisType::RackMount;
507cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
5087164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5097164bc62SChau Ly                                 chassisId);
5101476687dSEd Tanous         asyncResp->res
511cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
512ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
513ef4c65b7SEd Tanous                                 chassisId);
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;
524bd79bce8SPatrick Williams                 reference["@odata.id"] = boost::urls::format(
525bd79bce8SPatrick Williams                     "/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;
532e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
533e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
5341c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
5350fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
5361c8fba97SJames Feist 
537476b9cc5STejas Patil         const std::string assetTagInterface =
5380fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
539523d4868SLogananth Sundararaj         const std::string replaceableInterface =
540523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
541b4d593f1SCarson Labrado         const std::string revisionInterface =
542b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
543523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
544523d4868SLogananth Sundararaj         {
545523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
546476b9cc5STejas Patil             {
5471e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
548002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
549002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
5507164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
5511e1e598dSJonathan Doman                                            const std::string& property) {
5528a592810SEd Tanous                         if (ec2)
553476b9cc5STejas Patil                         {
554bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
555bd79bce8SPatrick Williams                                 "DBus response error for AssetTag: {}", ec2);
556476b9cc5STejas Patil                             messages::internalError(asyncResp->res);
557476b9cc5STejas Patil                             return;
558476b9cc5STejas Patil                         }
559002d39b4SEd Tanous                         asyncResp->res.jsonValue["AssetTag"] = property;
5601e1e598dSJonathan Doman                     });
561476b9cc5STejas Patil             }
562523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
563523d4868SLogananth Sundararaj             {
564523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
565523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
566523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
5677164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
568523d4868SLogananth Sundararaj                                            const bool property) {
569523d4868SLogananth Sundararaj                         if (ec2)
570523d4868SLogananth Sundararaj                         {
57162598e31SEd Tanous                             BMCWEB_LOG_ERROR(
572bd79bce8SPatrick Williams                                 "DBus response error for HotPluggable: {}",
573bd79bce8SPatrick Williams                                 ec2);
574523d4868SLogananth Sundararaj                             messages::internalError(asyncResp->res);
575523d4868SLogananth Sundararaj                             return;
576523d4868SLogananth Sundararaj                         }
577523d4868SLogananth Sundararaj                         asyncResp->res.jsonValue["HotPluggable"] = property;
578523d4868SLogananth Sundararaj                     });
579523d4868SLogananth Sundararaj             }
580b4d593f1SCarson Labrado             else if (interface == revisionInterface)
581b4d593f1SCarson Labrado             {
582b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
583b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
584b4d593f1SCarson Labrado                     revisionInterface, "Version",
585b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
586b4d593f1SCarson Labrado                                            const std::string& property) {
587b4d593f1SCarson Labrado                         if (ec2)
588b4d593f1SCarson Labrado                         {
589bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
590bd79bce8SPatrick Williams                                 "DBus response error for Version: {}", ec2);
591b4d593f1SCarson Labrado                             messages::internalError(asyncResp->res);
592b4d593f1SCarson Labrado                             return;
593b4d593f1SCarson Labrado                         }
594b4d593f1SCarson Labrado                         asyncResp->res.jsonValue["Version"] = property;
595b4d593f1SCarson Labrado                     });
596b4d593f1SCarson Labrado             }
597523d4868SLogananth Sundararaj         }
598476b9cc5STejas Patil 
5991c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
6001c8fba97SJames Feist         {
6017164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
6021c8fba97SJames Feist             {
6031c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
60459a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
6051c8fba97SJames Feist                 break;
6061c8fba97SJames Feist             }
6071c8fba97SJames Feist         }
6081c8fba97SJames Feist 
60986d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
61086d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
61186d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6127164bc62SChau Ly             [asyncResp, chassisId,
6137164bc62SChau Ly              path](const boost::system::error_code&,
614cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6157164bc62SChau Ly                 handleDecoratorAssetProperties(asyncResp, chassisId, path,
6167164bc62SChau Ly                                                propertiesList);
61786d89ed7SKrzysztof Grobelny             });
6182c37b4b0SSharad Yadav 
619308f70c7SWilly Tu         for (const auto& interface : interfaces2)
6202c37b4b0SSharad Yadav         {
621308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
6222c37b4b0SSharad Yadav             {
623308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
6242c37b4b0SSharad Yadav             }
625cf7eba09SNan Zhou             else if (interface ==
6260fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
6272c37b4b0SSharad Yadav             {
628002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
6292c37b4b0SSharad Yadav             }
6302c37b4b0SSharad Yadav         }
6312c37b4b0SSharad Yadav 
632daf36e2eSEd Tanous         return;
633daf36e2eSEd Tanous     }
634e0d918bcSEd Tanous 
635daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
636d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
6377164bc62SChau Ly }
638c181942fSQiang XU 
6397164bc62SChau Ly inline void
6407164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
6417164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6427164bc62SChau Ly                      const std::string& chassisId)
6437164bc62SChau Ly {
6447164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6457164bc62SChau Ly     {
6467164bc62SChau Ly         return;
6477164bc62SChau Ly     }
6487164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
6497164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
6507164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
6517164bc62SChau Ly 
6527164bc62SChau Ly     dbus::utility::getSubTree(
6537164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
6547164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
6557164bc62SChau Ly 
6567164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
6577164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
6587164bc62SChau Ly 
6597164bc62SChau Ly     dbus::utility::getSubTree(
6607164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
6617164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
662cf7eba09SNan Zhou }
6631c8fba97SJames Feist 
664cf7eba09SNan Zhou inline void
665cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
6667e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
667cf7eba09SNan Zhou                        const std::string& param)
668cf7eba09SNan Zhou {
6693ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
67045ca1b86SEd Tanous     {
67145ca1b86SEd Tanous         return;
67245ca1b86SEd Tanous     }
6739f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
6741c8fba97SJames Feist     std::optional<std::string> indicatorLed;
6751c8fba97SJames Feist 
6767e860f15SJohn Edward Broadbent     if (param.empty())
6771c8fba97SJames Feist     {
6781c8fba97SJames Feist         return;
6791c8fba97SJames Feist     }
6801c8fba97SJames Feist 
681*afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
682*afc474aeSMyung Bae             req, asyncResp->res, //
683*afc474aeSMyung Bae             "IndicatorLED", indicatorLed, //
684*afc474aeSMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
685*afc474aeSMyung Bae             ))
6861c8fba97SJames Feist     {
6871c8fba97SJames Feist         return;
6881c8fba97SJames Feist     }
6891c8fba97SJames Feist 
6909f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6919f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6921c8fba97SJames Feist     {
6931c8fba97SJames Feist         return; // delete this when we support more patch properties
6941c8fba97SJames Feist     }
695d6aa0093SGunnar Mills     if (indicatorLed)
696d6aa0093SGunnar Mills     {
6977e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6987e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6990fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
700d6aa0093SGunnar Mills     }
7011c8fba97SJames Feist 
702e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
7031c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
7041c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
7051c8fba97SJames Feist 
7067e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7071c8fba97SJames Feist 
708e99073f5SGeorge Liu     dbus::utility::getSubTree(
709e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
710cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7115e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
712b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7131c8fba97SJames Feist             if (ec)
7141c8fba97SJames Feist             {
71562598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7161c8fba97SJames Feist                 messages::internalError(asyncResp->res);
7171c8fba97SJames Feist                 return;
7181c8fba97SJames Feist             }
7191c8fba97SJames Feist 
7201c8fba97SJames Feist             // Iterate over all retrieved ObjectPaths.
721bd79bce8SPatrick Williams             for (const std::pair<std::string,
722bd79bce8SPatrick Williams                                  std::vector<std::pair<
723bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
7241214b7e7SGunnar Mills                      object : subtree)
7251c8fba97SJames Feist             {
7261c8fba97SJames Feist                 const std::string& path = object.first;
727bd79bce8SPatrick Williams                 const std::vector<
728bd79bce8SPatrick Williams                     std::pair<std::string, std::vector<std::string>>>&
7291214b7e7SGunnar Mills                     connectionNames = object.second;
7301c8fba97SJames Feist 
731997093ebSGeorge Liu                 sdbusplus::message::object_path objPath(path);
732997093ebSGeorge Liu                 if (objPath.filename() != chassisId)
7331c8fba97SJames Feist                 {
7341c8fba97SJames Feist                     continue;
7351c8fba97SJames Feist                 }
7361c8fba97SJames Feist 
73726f6976fSEd Tanous                 if (connectionNames.empty())
7381c8fba97SJames Feist                 {
73962598e31SEd Tanous                     BMCWEB_LOG_ERROR("Got 0 Connection names");
7401c8fba97SJames Feist                     continue;
7411c8fba97SJames Feist                 }
7421c8fba97SJames Feist 
74323a21a1cSEd Tanous                 const std::vector<std::string>& interfaces3 =
7441c8fba97SJames Feist                     connectionNames[0].second;
7451c8fba97SJames Feist 
746e5ae9c1cSGeorge Liu                 const std::array<const char*, 3> hasIndicatorLed = {
747e5ae9c1cSGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Chassis",
7481c8fba97SJames Feist                     "xyz.openbmc_project.Inventory.Item.Panel",
7490fda0f12SGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7501c8fba97SJames Feist                 bool indicatorChassis = false;
7511c8fba97SJames Feist                 for (const char* interface : hasIndicatorLed)
7521c8fba97SJames Feist                 {
7533544d2a7SEd Tanous                     if (std::ranges::find(interfaces3, interface) !=
7543544d2a7SEd Tanous                         interfaces3.end())
7551c8fba97SJames Feist                     {
7561c8fba97SJames Feist                         indicatorChassis = true;
7571c8fba97SJames Feist                         break;
7581c8fba97SJames Feist                     }
7591c8fba97SJames Feist                 }
7609f8bfa7cSGunnar Mills                 if (locationIndicatorActive)
7619f8bfa7cSGunnar Mills                 {
7629f8bfa7cSGunnar Mills                     if (indicatorChassis)
7639f8bfa7cSGunnar Mills                     {
764bd79bce8SPatrick Williams                         setSystemLocationIndicatorActive(
765bd79bce8SPatrick Williams                             asyncResp, *locationIndicatorActive);
7669f8bfa7cSGunnar Mills                     }
7679f8bfa7cSGunnar Mills                     else
7689f8bfa7cSGunnar Mills                     {
769002d39b4SEd Tanous                         messages::propertyUnknown(asyncResp->res,
770002d39b4SEd Tanous                                                   "LocationIndicatorActive");
7719f8bfa7cSGunnar Mills                     }
7729f8bfa7cSGunnar Mills                 }
7739f8bfa7cSGunnar Mills                 if (indicatorLed)
7749f8bfa7cSGunnar Mills                 {
7751c8fba97SJames Feist                     if (indicatorChassis)
7761c8fba97SJames Feist                     {
777f23b7296SEd Tanous                         setIndicatorLedState(asyncResp, *indicatorLed);
7781c8fba97SJames Feist                     }
7791c8fba97SJames Feist                     else
7801c8fba97SJames Feist                     {
781bd79bce8SPatrick Williams                         messages::propertyUnknown(asyncResp->res,
782bd79bce8SPatrick Williams                                                   "IndicatorLED");
7831c8fba97SJames Feist                     }
7841c8fba97SJames Feist                 }
7851c8fba97SJames Feist                 return;
7861c8fba97SJames Feist             }
7871c8fba97SJames Feist 
788d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
789e99073f5SGeorge Liu         });
790cf7eba09SNan Zhou }
791cf7eba09SNan Zhou 
792cf7eba09SNan Zhou /**
793cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
794cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
795cf7eba09SNan Zhou  */
796cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
797cf7eba09SNan Zhou {
798cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
799cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
800cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
801cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
802cf7eba09SNan Zhou 
803cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
804cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
805cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
806cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8071c8fba97SJames Feist }
808dd99e04bSP.K. Lee 
8098d1b46d7Szhanghch05 inline void
8108d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
811dd99e04bSP.K. Lee {
8127a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
813c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
814c3b3c92aSVijay Khemka 
815c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8167a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8177a1dbc48SGeorge Liu         "/", 0, interfaces,
818b9d36b47SEd Tanous         [asyncResp](
8197a1dbc48SGeorge Liu             const boost::system::error_code& ec,
820b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
821c3b3c92aSVijay Khemka             if (ec)
822c3b3c92aSVijay Khemka             {
82362598e31SEd Tanous                 BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
824c3b3c92aSVijay Khemka                 messages::internalError(asyncResp->res);
825c3b3c92aSVijay Khemka                 return;
826c3b3c92aSVijay Khemka             }
827c3b3c92aSVijay Khemka 
828dd99e04bSP.K. Lee             const char* processName = "xyz.openbmc_project.State.Chassis";
829dd99e04bSP.K. Lee             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
830dd99e04bSP.K. Lee             const char* destProperty = "RequestedPowerTransition";
831dd99e04bSP.K. Lee             const std::string propertyValue =
832dd99e04bSP.K. Lee                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
833bd79bce8SPatrick Williams             std::string objectPath =
834bd79bce8SPatrick Williams                 "/xyz/openbmc_project/state/chassis_system0";
835c3b3c92aSVijay Khemka 
836c3b3c92aSVijay Khemka             /* Look for system reset chassis path */
837bd79bce8SPatrick Williams             if ((std::ranges::find(chassisList, objectPath)) ==
838bd79bce8SPatrick Williams                 chassisList.end())
839c3b3c92aSVijay Khemka             {
840c3b3c92aSVijay Khemka                 /* We prefer to reset the full chassis_system, but if it doesn't
841c3b3c92aSVijay Khemka                  * exist on some platforms, fall back to a host-only power reset
842c3b3c92aSVijay Khemka                  */
843c3b3c92aSVijay Khemka                 objectPath = "/xyz/openbmc_project/state/chassis0";
844c3b3c92aSVijay Khemka             }
845dd99e04bSP.K. Lee 
846e93abac6SGinu George             setDbusProperty(asyncResp, "ResetType", processName, objectPath,
847e93abac6SGinu George                             interfaceName, destProperty, propertyValue);
8487a1dbc48SGeorge Liu         });
849dd99e04bSP.K. Lee }
850dd99e04bSP.K. Lee 
851cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
852cf7eba09SNan Zhou     App& app, const crow::Request& req,
8537e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
854cf7eba09SNan Zhou     const std::string& /*chassisId*/)
855cf7eba09SNan Zhou {
8563ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
85745ca1b86SEd Tanous     {
85845ca1b86SEd Tanous         return;
85945ca1b86SEd Tanous     }
86062598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
861dd99e04bSP.K. Lee 
862dd99e04bSP.K. Lee     std::string resetType;
863dd99e04bSP.K. Lee 
864cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
865dd99e04bSP.K. Lee     {
866dd99e04bSP.K. Lee         return;
867dd99e04bSP.K. Lee     }
868dd99e04bSP.K. Lee 
869dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
870dd99e04bSP.K. Lee     {
87162598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
872002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
873002d39b4SEd Tanous                                               "ResetType");
874dd99e04bSP.K. Lee 
875dd99e04bSP.K. Lee         return;
876dd99e04bSP.K. Lee     }
877dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
878dd99e04bSP.K. Lee }
8791cb1a9e6SAppaRao Puli 
8801cb1a9e6SAppaRao Puli /**
881cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
882cf7eba09SNan Zhou  * action.
883cf7eba09SNan Zhou  * Function handles POST method request.
884cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8851cb1a9e6SAppaRao Puli  */
886cf7eba09SNan Zhou 
887cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8881cb1a9e6SAppaRao Puli {
889cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
890cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
891cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
892cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
893cf7eba09SNan Zhou }
894cf7eba09SNan Zhou 
895cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
896cf7eba09SNan Zhou     App& app, const crow::Request& req,
8977e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
898cf7eba09SNan Zhou     const std::string& chassisId)
899cf7eba09SNan Zhou {
9003ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
9011cb1a9e6SAppaRao Puli     {
90245ca1b86SEd Tanous         return;
90345ca1b86SEd Tanous     }
904cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
905ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
906ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9071476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9081476687dSEd Tanous 
9091476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9105b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9115b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9125b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9135b9e95a1SNan Zhou     parameter["Required"] = true;
914539d8c6bSEd Tanous     parameter["DataType"] = action_info::ParameterTypes::String;
9151476687dSEd Tanous     nlohmann::json::array_t allowed;
916ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9175b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
918ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9195b9e95a1SNan Zhou 
9201476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
921cf7eba09SNan Zhou }
922cf7eba09SNan Zhou 
923cf7eba09SNan Zhou /**
924cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
925cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
926cf7eba09SNan Zhou  */
927cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
928cf7eba09SNan Zhou {
929cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
930cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
931cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
932cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9331cb1a9e6SAppaRao Puli }
9341cb1a9e6SAppaRao Puli 
935e37f8451SRapkiewicz, Pawel } // namespace redfish
936