xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 6be832e2963e9d720dd95543358eca380c5e52d2)
1e37f8451SRapkiewicz, Pawel /*
2*6be832e2SEd Tanous Copyright (c) 2018 Intel Corporation
3*6be832e2SEd Tanous 
4*6be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License");
5*6be832e2SEd Tanous you may not use this file except in compliance with the License.
6*6be832e2SEd Tanous You may obtain a copy of the License at
7*6be832e2SEd Tanous 
8*6be832e2SEd Tanous       http://www.apache.org/licenses/LICENSE-2.0
9*6be832e2SEd Tanous 
10*6be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software
11*6be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS,
12*6be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6be832e2SEd Tanous See the License for the specific language governing permissions and
14*6be832e2SEd 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 
68115ed6780SWilly Tu     if (!json_util::readJsonPatch(
6827e860f15SJohn Edward Broadbent             req, asyncResp->res, "LocationIndicatorActive",
6837e860f15SJohn Edward Broadbent             locationIndicatorActive, "IndicatorLED", indicatorLed))
6841c8fba97SJames Feist     {
6851c8fba97SJames Feist         return;
6861c8fba97SJames Feist     }
6871c8fba97SJames Feist 
6889f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
6899f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
6901c8fba97SJames Feist     {
6911c8fba97SJames Feist         return; // delete this when we support more patch properties
6921c8fba97SJames Feist     }
693d6aa0093SGunnar Mills     if (indicatorLed)
694d6aa0093SGunnar Mills     {
6957e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
6967e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
6970fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
698d6aa0093SGunnar Mills     }
6991c8fba97SJames Feist 
700e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
7011c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
7021c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
7031c8fba97SJames Feist 
7047e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7051c8fba97SJames Feist 
706e99073f5SGeorge Liu     dbus::utility::getSubTree(
707e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
708cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7095e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
710b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7111c8fba97SJames Feist             if (ec)
7121c8fba97SJames Feist             {
71362598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
7141c8fba97SJames Feist                 messages::internalError(asyncResp->res);
7151c8fba97SJames Feist                 return;
7161c8fba97SJames Feist             }
7171c8fba97SJames Feist 
7181c8fba97SJames Feist             // Iterate over all retrieved ObjectPaths.
719bd79bce8SPatrick Williams             for (const std::pair<std::string,
720bd79bce8SPatrick Williams                                  std::vector<std::pair<
721bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
7221214b7e7SGunnar Mills                      object : subtree)
7231c8fba97SJames Feist             {
7241c8fba97SJames Feist                 const std::string& path = object.first;
725bd79bce8SPatrick Williams                 const std::vector<
726bd79bce8SPatrick Williams                     std::pair<std::string, std::vector<std::string>>>&
7271214b7e7SGunnar Mills                     connectionNames = object.second;
7281c8fba97SJames Feist 
729997093ebSGeorge Liu                 sdbusplus::message::object_path objPath(path);
730997093ebSGeorge Liu                 if (objPath.filename() != chassisId)
7311c8fba97SJames Feist                 {
7321c8fba97SJames Feist                     continue;
7331c8fba97SJames Feist                 }
7341c8fba97SJames Feist 
73526f6976fSEd Tanous                 if (connectionNames.empty())
7361c8fba97SJames Feist                 {
73762598e31SEd Tanous                     BMCWEB_LOG_ERROR("Got 0 Connection names");
7381c8fba97SJames Feist                     continue;
7391c8fba97SJames Feist                 }
7401c8fba97SJames Feist 
74123a21a1cSEd Tanous                 const std::vector<std::string>& interfaces3 =
7421c8fba97SJames Feist                     connectionNames[0].second;
7431c8fba97SJames Feist 
744e5ae9c1cSGeorge Liu                 const std::array<const char*, 3> hasIndicatorLed = {
745e5ae9c1cSGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Chassis",
7461c8fba97SJames Feist                     "xyz.openbmc_project.Inventory.Item.Panel",
7470fda0f12SGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
7481c8fba97SJames Feist                 bool indicatorChassis = false;
7491c8fba97SJames Feist                 for (const char* interface : hasIndicatorLed)
7501c8fba97SJames Feist                 {
7513544d2a7SEd Tanous                     if (std::ranges::find(interfaces3, interface) !=
7523544d2a7SEd Tanous                         interfaces3.end())
7531c8fba97SJames Feist                     {
7541c8fba97SJames Feist                         indicatorChassis = true;
7551c8fba97SJames Feist                         break;
7561c8fba97SJames Feist                     }
7571c8fba97SJames Feist                 }
7589f8bfa7cSGunnar Mills                 if (locationIndicatorActive)
7599f8bfa7cSGunnar Mills                 {
7609f8bfa7cSGunnar Mills                     if (indicatorChassis)
7619f8bfa7cSGunnar Mills                     {
762bd79bce8SPatrick Williams                         setSystemLocationIndicatorActive(
763bd79bce8SPatrick Williams                             asyncResp, *locationIndicatorActive);
7649f8bfa7cSGunnar Mills                     }
7659f8bfa7cSGunnar Mills                     else
7669f8bfa7cSGunnar Mills                     {
767002d39b4SEd Tanous                         messages::propertyUnknown(asyncResp->res,
768002d39b4SEd Tanous                                                   "LocationIndicatorActive");
7699f8bfa7cSGunnar Mills                     }
7709f8bfa7cSGunnar Mills                 }
7719f8bfa7cSGunnar Mills                 if (indicatorLed)
7729f8bfa7cSGunnar Mills                 {
7731c8fba97SJames Feist                     if (indicatorChassis)
7741c8fba97SJames Feist                     {
775f23b7296SEd Tanous                         setIndicatorLedState(asyncResp, *indicatorLed);
7761c8fba97SJames Feist                     }
7771c8fba97SJames Feist                     else
7781c8fba97SJames Feist                     {
779bd79bce8SPatrick Williams                         messages::propertyUnknown(asyncResp->res,
780bd79bce8SPatrick Williams                                                   "IndicatorLED");
7811c8fba97SJames Feist                     }
7821c8fba97SJames Feist                 }
7831c8fba97SJames Feist                 return;
7841c8fba97SJames Feist             }
7851c8fba97SJames Feist 
786d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
787e99073f5SGeorge Liu         });
788cf7eba09SNan Zhou }
789cf7eba09SNan Zhou 
790cf7eba09SNan Zhou /**
791cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
792cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
793cf7eba09SNan Zhou  */
794cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
795cf7eba09SNan Zhou {
796cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
797cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
798cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
799cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
800cf7eba09SNan Zhou 
801cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
802cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
803cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
804cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8051c8fba97SJames Feist }
806dd99e04bSP.K. Lee 
8078d1b46d7Szhanghch05 inline void
8088d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
809dd99e04bSP.K. Lee {
8107a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
811c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
812c3b3c92aSVijay Khemka 
813c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
8147a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
8157a1dbc48SGeorge Liu         "/", 0, interfaces,
816b9d36b47SEd Tanous         [asyncResp](
8177a1dbc48SGeorge Liu             const boost::system::error_code& ec,
818b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
819c3b3c92aSVijay Khemka             if (ec)
820c3b3c92aSVijay Khemka             {
82162598e31SEd Tanous                 BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
822c3b3c92aSVijay Khemka                 messages::internalError(asyncResp->res);
823c3b3c92aSVijay Khemka                 return;
824c3b3c92aSVijay Khemka             }
825c3b3c92aSVijay Khemka 
826dd99e04bSP.K. Lee             const char* processName = "xyz.openbmc_project.State.Chassis";
827dd99e04bSP.K. Lee             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
828dd99e04bSP.K. Lee             const char* destProperty = "RequestedPowerTransition";
829dd99e04bSP.K. Lee             const std::string propertyValue =
830dd99e04bSP.K. Lee                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
831bd79bce8SPatrick Williams             std::string objectPath =
832bd79bce8SPatrick Williams                 "/xyz/openbmc_project/state/chassis_system0";
833c3b3c92aSVijay Khemka 
834c3b3c92aSVijay Khemka             /* Look for system reset chassis path */
835bd79bce8SPatrick Williams             if ((std::ranges::find(chassisList, objectPath)) ==
836bd79bce8SPatrick Williams                 chassisList.end())
837c3b3c92aSVijay Khemka             {
838c3b3c92aSVijay Khemka                 /* We prefer to reset the full chassis_system, but if it doesn't
839c3b3c92aSVijay Khemka                  * exist on some platforms, fall back to a host-only power reset
840c3b3c92aSVijay Khemka                  */
841c3b3c92aSVijay Khemka                 objectPath = "/xyz/openbmc_project/state/chassis0";
842c3b3c92aSVijay Khemka             }
843dd99e04bSP.K. Lee 
844e93abac6SGinu George             setDbusProperty(asyncResp, "ResetType", processName, objectPath,
845e93abac6SGinu George                             interfaceName, destProperty, propertyValue);
8467a1dbc48SGeorge Liu         });
847dd99e04bSP.K. Lee }
848dd99e04bSP.K. Lee 
849cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
850cf7eba09SNan Zhou     App& app, const crow::Request& req,
8517e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
852cf7eba09SNan Zhou     const std::string& /*chassisId*/)
853cf7eba09SNan Zhou {
8543ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
85545ca1b86SEd Tanous     {
85645ca1b86SEd Tanous         return;
85745ca1b86SEd Tanous     }
85862598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
859dd99e04bSP.K. Lee 
860dd99e04bSP.K. Lee     std::string resetType;
861dd99e04bSP.K. Lee 
862cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
863dd99e04bSP.K. Lee     {
864dd99e04bSP.K. Lee         return;
865dd99e04bSP.K. Lee     }
866dd99e04bSP.K. Lee 
867dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
868dd99e04bSP.K. Lee     {
86962598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
870002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
871002d39b4SEd Tanous                                               "ResetType");
872dd99e04bSP.K. Lee 
873dd99e04bSP.K. Lee         return;
874dd99e04bSP.K. Lee     }
875dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
876dd99e04bSP.K. Lee }
8771cb1a9e6SAppaRao Puli 
8781cb1a9e6SAppaRao Puli /**
879cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
880cf7eba09SNan Zhou  * action.
881cf7eba09SNan Zhou  * Function handles POST method request.
882cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
8831cb1a9e6SAppaRao Puli  */
884cf7eba09SNan Zhou 
885cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
8861cb1a9e6SAppaRao Puli {
887cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
888cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
889cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
890cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
891cf7eba09SNan Zhou }
892cf7eba09SNan Zhou 
893cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
894cf7eba09SNan Zhou     App& app, const crow::Request& req,
8957e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
896cf7eba09SNan Zhou     const std::string& chassisId)
897cf7eba09SNan Zhou {
8983ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
8991cb1a9e6SAppaRao Puli     {
90045ca1b86SEd Tanous         return;
90145ca1b86SEd Tanous     }
902cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
903ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
904ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9051476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9061476687dSEd Tanous 
9071476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9085b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9095b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9105b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9115b9e95a1SNan Zhou     parameter["Required"] = true;
912539d8c6bSEd Tanous     parameter["DataType"] = action_info::ParameterTypes::String;
9131476687dSEd Tanous     nlohmann::json::array_t allowed;
914ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
9155b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
916ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
9175b9e95a1SNan Zhou 
9181476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
919cf7eba09SNan Zhou }
920cf7eba09SNan Zhou 
921cf7eba09SNan Zhou /**
922cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
923cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
924cf7eba09SNan Zhou  */
925cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
926cf7eba09SNan Zhou {
927cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
928cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
929cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
930cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
9311cb1a9e6SAppaRao Puli }
9321cb1a9e6SAppaRao Puli 
933e37f8451SRapkiewicz, Pawel } // namespace redfish
934