xref: /openbmc/bmcweb/features/redfish/lib/chassis.hpp (revision 2952f648b5b02e7439ce62427a22b6d5dc7d454c)
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>
38*2952f648SJoseph-Jonathan Salzano #include <memory>
393544d2a7SEd Tanous #include <ranges>
407a1dbc48SGeorge Liu #include <string_view>
417a1dbc48SGeorge Liu 
421abe55efSEd Tanous namespace redfish
431abe55efSEd Tanous {
44e37f8451SRapkiewicz, Pawel 
45*2952f648SJoseph-Jonathan Salzano inline chassis::ChassisType
46*2952f648SJoseph-Jonathan Salzano     translateChassisTypeToRedfish(const std::string_view& chassisType)
47*2952f648SJoseph-Jonathan Salzano {
48*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
49*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Blade")
50*2952f648SJoseph-Jonathan Salzano     {
51*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Blade;
52*2952f648SJoseph-Jonathan Salzano     }
53*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
54*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Component")
55*2952f648SJoseph-Jonathan Salzano     {
56*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Component;
57*2952f648SJoseph-Jonathan Salzano     }
58*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
59*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Enclosure")
60*2952f648SJoseph-Jonathan Salzano     {
61*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Enclosure;
62*2952f648SJoseph-Jonathan Salzano     }
63*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
64*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Module")
65*2952f648SJoseph-Jonathan Salzano     {
66*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Module;
67*2952f648SJoseph-Jonathan Salzano     }
68*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
69*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.RackMount")
70*2952f648SJoseph-Jonathan Salzano     {
71*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::RackMount;
72*2952f648SJoseph-Jonathan Salzano     }
73*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
74*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StandAlone")
75*2952f648SJoseph-Jonathan Salzano     {
76*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StandAlone;
77*2952f648SJoseph-Jonathan Salzano     }
78*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
79*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.StorageEnclosure")
80*2952f648SJoseph-Jonathan Salzano     {
81*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::StorageEnclosure;
82*2952f648SJoseph-Jonathan Salzano     }
83*2952f648SJoseph-Jonathan Salzano     if (chassisType ==
84*2952f648SJoseph-Jonathan Salzano         "xyz.openbmc_project.Inventory.Item.Chassis.ChassisType.Zone")
85*2952f648SJoseph-Jonathan Salzano     {
86*2952f648SJoseph-Jonathan Salzano         return chassis::ChassisType::Zone;
87*2952f648SJoseph-Jonathan Salzano     }
88*2952f648SJoseph-Jonathan Salzano     return chassis::ChassisType::Invalid;
89*2952f648SJoseph-Jonathan Salzano }
90*2952f648SJoseph-Jonathan Salzano 
91e37f8451SRapkiewicz, Pawel /**
925e577bc1SWilly Tu  * @brief Retrieves resources over dbus to link to the chassis
935e577bc1SWilly Tu  *
945e577bc1SWilly Tu  * @param[in] asyncResp  - Shared pointer for completing asynchronous
955e577bc1SWilly Tu  * calls
965e577bc1SWilly Tu  * @param[in] path       - Chassis dbus path to look for the storage.
975e577bc1SWilly Tu  *
985e577bc1SWilly Tu  * Calls the Association endpoints on the path + "/storage" and add the link of
995e577bc1SWilly Tu  * json["Links"]["Storage@odata.count"] =
1005e577bc1SWilly Tu  *    {"@odata.id", "/redfish/v1/Storage/" + resourceId}
1015e577bc1SWilly Tu  *
1025e577bc1SWilly Tu  * @return None.
1035e577bc1SWilly Tu  */
1045e577bc1SWilly Tu inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1055e577bc1SWilly Tu                            const sdbusplus::message::object_path& path)
1065e577bc1SWilly Tu {
1075e577bc1SWilly Tu     sdbusplus::asio::getProperty<std::vector<std::string>>(
1085e577bc1SWilly Tu         *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
1095e577bc1SWilly Tu         (path / "storage").str, "xyz.openbmc_project.Association", "endpoints",
110d4b054c1SWilly Tu         [asyncResp](const boost::system::error_code& ec,
1115e577bc1SWilly Tu                     const std::vector<std::string>& storageList) {
1125e577bc1SWilly Tu             if (ec)
1135e577bc1SWilly Tu             {
11462598e31SEd Tanous                 BMCWEB_LOG_DEBUG("getStorageLink got DBUS response error");
1155e577bc1SWilly Tu                 return;
1165e577bc1SWilly Tu             }
1175e577bc1SWilly Tu 
1185e577bc1SWilly Tu             nlohmann::json::array_t storages;
1195e577bc1SWilly Tu             for (const std::string& storagePath : storageList)
1205e577bc1SWilly Tu             {
1215e577bc1SWilly Tu                 std::string id =
1225e577bc1SWilly Tu                     sdbusplus::message::object_path(storagePath).filename();
1235e577bc1SWilly Tu                 if (id.empty())
1245e577bc1SWilly Tu                 {
1255e577bc1SWilly Tu                     continue;
1265e577bc1SWilly Tu                 }
1275e577bc1SWilly Tu 
1285e577bc1SWilly Tu                 nlohmann::json::object_t storage;
129253f11b8SEd Tanous                 storage["@odata.id"] =
130253f11b8SEd Tanous                     boost::urls::format("/redfish/v1/Systems/{}/Storage/{}",
131253f11b8SEd Tanous                                         BMCWEB_REDFISH_SYSTEM_URI_NAME, id);
1325e577bc1SWilly Tu                 storages.emplace_back(std::move(storage));
1335e577bc1SWilly Tu             }
1345e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
1355e577bc1SWilly Tu                 storages.size();
1365e577bc1SWilly Tu             asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
1375e577bc1SWilly Tu         });
1385e577bc1SWilly Tu }
1395e577bc1SWilly Tu 
1405e577bc1SWilly Tu /**
141beeca0aeSGunnar Mills  * @brief Retrieves chassis state properties over dbus
142beeca0aeSGunnar Mills  *
143ac106bf6SEd Tanous  * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
144beeca0aeSGunnar Mills  *
145beeca0aeSGunnar Mills  * @return None.
146beeca0aeSGunnar Mills  */
147ac106bf6SEd Tanous inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
148beeca0aeSGunnar Mills {
1491e1e598dSJonathan Doman     // crow::connections::systemBus->async_method_call(
1501e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
1511e1e598dSJonathan Doman         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1521e1e598dSJonathan Doman         "/xyz/openbmc_project/state/chassis0",
1531e1e598dSJonathan Doman         "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
154ac106bf6SEd Tanous         [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
1551e1e598dSJonathan Doman                                           const std::string& chassisState) {
156beeca0aeSGunnar Mills             if (ec)
157beeca0aeSGunnar Mills             {
158a6e5e0abSCarson Labrado                 if (ec == boost::system::errc::host_unreachable)
159a6e5e0abSCarson Labrado                 {
160a6e5e0abSCarson Labrado                     // Service not available, no error, just don't return
161a6e5e0abSCarson Labrado                     // chassis state info
16262598e31SEd Tanous                     BMCWEB_LOG_DEBUG("Service not available {}", ec);
163a6e5e0abSCarson Labrado                     return;
164a6e5e0abSCarson Labrado                 }
16562598e31SEd Tanous                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
166ac106bf6SEd Tanous                 messages::internalError(asyncResp->res);
167beeca0aeSGunnar Mills                 return;
168beeca0aeSGunnar Mills             }
169beeca0aeSGunnar Mills 
17062598e31SEd Tanous             BMCWEB_LOG_DEBUG("Chassis state: {}", chassisState);
171beeca0aeSGunnar Mills             // Verify Chassis State
172bd79bce8SPatrick Williams             if (chassisState ==
173bd79bce8SPatrick Williams                 "xyz.openbmc_project.State.Chassis.PowerState.On")
174beeca0aeSGunnar Mills             {
175bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
176bd79bce8SPatrick Williams                     resource::PowerState::On;
177539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
178539d8c6bSEd Tanous                     resource::State::Enabled;
179beeca0aeSGunnar Mills             }
1801e1e598dSJonathan Doman             else if (chassisState ==
181beeca0aeSGunnar Mills                      "xyz.openbmc_project.State.Chassis.PowerState.Off")
182beeca0aeSGunnar Mills             {
183bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["PowerState"] =
184bd79bce8SPatrick Williams                     resource::PowerState::Off;
185539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Status"]["State"] =
186539d8c6bSEd Tanous                     resource::State::StandbyOffline;
187beeca0aeSGunnar Mills             }
1881e1e598dSJonathan Doman         });
189beeca0aeSGunnar Mills }
190beeca0aeSGunnar Mills 
191c181942fSQiang XU /**
192c181942fSQiang XU  * Retrieves physical security properties over dbus
193c181942fSQiang XU  */
1947164bc62SChau Ly inline void handlePhysicalSecurityGetSubTree(
1957164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196e99073f5SGeorge Liu     const boost::system::error_code& ec,
1977164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
1987164bc62SChau Ly {
199c181942fSQiang XU     if (ec)
200c181942fSQiang XU     {
2014e0453b1SGunnar Mills         // do not add err msg in redfish response, because this is not
202c181942fSQiang XU         //     mandatory property
20362598e31SEd Tanous         BMCWEB_LOG_INFO("DBUS error: no matched iface {}", ec);
204c181942fSQiang XU         return;
205c181942fSQiang XU     }
206c181942fSQiang XU     // Iterate over all retrieved ObjectPaths.
207c181942fSQiang XU     for (const auto& object : subtree)
208c181942fSQiang XU     {
209840a9ffcSPatrick Williams         if (!object.second.empty())
210c181942fSQiang XU         {
21189144a3aSEd Tanous             const auto& service = object.second.front();
2127164bc62SChau Ly 
2137164bc62SChau Ly             BMCWEB_LOG_DEBUG("Get intrusion status by service ");
2147164bc62SChau Ly 
2157164bc62SChau Ly             sdbusplus::asio::getProperty<std::string>(
2167164bc62SChau Ly                 *crow::connections::systemBus, service.first, object.first,
2177164bc62SChau Ly                 "xyz.openbmc_project.Chassis.Intrusion", "Status",
2187164bc62SChau Ly                 [asyncResp](const boost::system::error_code& ec1,
2197164bc62SChau Ly                             const std::string& value) {
2207164bc62SChau Ly                     if (ec1)
2217164bc62SChau Ly                     {
222bd79bce8SPatrick Williams                         // do not add err msg in redfish response, because this
223bd79bce8SPatrick Williams                         // is not
2247164bc62SChau Ly                         //     mandatory property
2257164bc62SChau Ly                         BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
2267164bc62SChau Ly                         return;
2277164bc62SChau Ly                     }
228bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["PhysicalSecurity"]
229bd79bce8SPatrick Williams                                             ["IntrusionSensorNumber"] = 1;
2307164bc62SChau Ly                     asyncResp->res
231bd79bce8SPatrick Williams                         .jsonValue["PhysicalSecurity"]["IntrusionSensor"] =
232bd79bce8SPatrick Williams                         value;
2337164bc62SChau Ly                 });
2347164bc62SChau Ly 
235c181942fSQiang XU             return;
236c181942fSQiang XU         }
237c181942fSQiang XU     }
238c181942fSQiang XU }
239c181942fSQiang XU 
240cf7eba09SNan Zhou inline void handleChassisCollectionGet(
241cf7eba09SNan Zhou     App& app, const crow::Request& req,
242cf7eba09SNan Zhou     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2431abe55efSEd Tanous {
2443ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
24545ca1b86SEd Tanous     {
24645ca1b86SEd Tanous         return;
24745ca1b86SEd Tanous     }
2488d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.type"] =
2498d1b46d7Szhanghch05         "#ChassisCollection.ChassisCollection";
2508d1b46d7Szhanghch05     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
2518d1b46d7Szhanghch05     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
252e37f8451SRapkiewicz, Pawel 
2537a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces{
2547a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Board",
2557a1dbc48SGeorge Liu         "xyz.openbmc_project.Inventory.Item.Chassis"};
25602f6ff19SGunnar Mills     collection_util::getCollectionMembers(
25736b5f1edSLakshmi Yadlapati         asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces,
25836b5f1edSLakshmi Yadlapati         "/xyz/openbmc_project/inventory");
259cf7eba09SNan Zhou }
260cf7eba09SNan Zhou 
261a5617496SJie Yang inline void getChassisContainedBy(
262a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
263a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
26428ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& upstreamChassisPaths)
265a5617496SJie Yang {
266a5617496SJie Yang     if (ec)
267a5617496SJie Yang     {
268a5617496SJie Yang         if (ec.value() != EBADR)
269a5617496SJie Yang         {
27062598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
271a5617496SJie Yang             messages::internalError(asyncResp->res);
272a5617496SJie Yang         }
273a5617496SJie Yang         return;
274a5617496SJie Yang     }
275a5617496SJie Yang     if (upstreamChassisPaths.empty())
276a5617496SJie Yang     {
277a5617496SJie Yang         return;
278a5617496SJie Yang     }
279a5617496SJie Yang     if (upstreamChassisPaths.size() > 1)
280a5617496SJie Yang     {
2818ece0e45SEd Tanous         BMCWEB_LOG_ERROR("{} is contained by multiple chassis", chassisId);
282a5617496SJie Yang         messages::internalError(asyncResp->res);
283a5617496SJie Yang         return;
284a5617496SJie Yang     }
285a5617496SJie Yang 
286a5617496SJie Yang     sdbusplus::message::object_path upstreamChassisPath(
287a5617496SJie Yang         upstreamChassisPaths[0]);
288a5617496SJie Yang     std::string upstreamChassis = upstreamChassisPath.filename();
289a5617496SJie Yang     if (upstreamChassis.empty())
290a5617496SJie Yang     {
29162598e31SEd Tanous         BMCWEB_LOG_WARNING("Malformed upstream Chassis path {} on {}",
29262598e31SEd Tanous                            upstreamChassisPath.str, chassisId);
293a5617496SJie Yang         return;
294a5617496SJie Yang     }
295a5617496SJie Yang 
296a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["ContainedBy"]["@odata.id"] =
297a5617496SJie Yang         boost::urls::format("/redfish/v1/Chassis/{}", upstreamChassis);
298a5617496SJie Yang }
299a5617496SJie Yang 
300a5617496SJie Yang inline void getChassisContains(
301a5617496SJie Yang     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
302a5617496SJie Yang     const std::string& chassisId, const boost::system::error_code& ec,
30328ee563eSMyung Bae     const dbus::utility::MapperGetSubTreePathsResponse& downstreamChassisPaths)
304a5617496SJie Yang {
305a5617496SJie Yang     if (ec)
306a5617496SJie Yang     {
307a5617496SJie Yang         if (ec.value() != EBADR)
308a5617496SJie Yang         {
30962598e31SEd Tanous             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
310a5617496SJie Yang             messages::internalError(asyncResp->res);
311a5617496SJie Yang         }
312a5617496SJie Yang         return;
313a5617496SJie Yang     }
314a5617496SJie Yang     if (downstreamChassisPaths.empty())
315a5617496SJie Yang     {
316a5617496SJie Yang         return;
317a5617496SJie Yang     }
318a5617496SJie Yang     nlohmann::json& jValue = asyncResp->res.jsonValue["Links"]["Contains"];
319a5617496SJie Yang     if (!jValue.is_array())
320a5617496SJie Yang     {
321a5617496SJie Yang         // Create the array if it was empty
322a5617496SJie Yang         jValue = nlohmann::json::array();
323a5617496SJie Yang     }
324a5617496SJie Yang     for (const auto& p : downstreamChassisPaths)
325a5617496SJie Yang     {
326a5617496SJie Yang         sdbusplus::message::object_path downstreamChassisPath(p);
327a5617496SJie Yang         std::string downstreamChassis = downstreamChassisPath.filename();
328a5617496SJie Yang         if (downstreamChassis.empty())
329a5617496SJie Yang         {
33062598e31SEd Tanous             BMCWEB_LOG_WARNING("Malformed downstream Chassis path {} on {}",
33162598e31SEd Tanous                                downstreamChassisPath.str, chassisId);
332a5617496SJie Yang             continue;
333a5617496SJie Yang         }
334a5617496SJie Yang         nlohmann::json link;
335bd79bce8SPatrick Williams         link["@odata.id"] =
336bd79bce8SPatrick Williams             boost::urls::format("/redfish/v1/Chassis/{}", downstreamChassis);
337a5617496SJie Yang         jValue.push_back(std::move(link));
338a5617496SJie Yang     }
339a5617496SJie Yang     asyncResp->res.jsonValue["Links"]["Contains@odata.count"] = jValue.size();
340a5617496SJie Yang }
341a5617496SJie Yang 
342bd79bce8SPatrick Williams inline void getChassisConnectivity(
343bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
344bd79bce8SPatrick Williams     const std::string& chassisId, const std::string& chassisPath)
345a5617496SJie Yang {
34662598e31SEd Tanous     BMCWEB_LOG_DEBUG("Get chassis connectivity");
347a5617496SJie Yang 
34828ee563eSMyung Bae     constexpr std::array<std::string_view, 2> interfaces{
34928ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Board",
35028ee563eSMyung Bae         "xyz.openbmc_project.Inventory.Item.Chassis"};
35128ee563eSMyung Bae 
35228ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
353a5617496SJie Yang         chassisPath + "/contained_by",
35428ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
35528ee563eSMyung Bae         interfaces,
356a5617496SJie Yang         std::bind_front(getChassisContainedBy, asyncResp, chassisId));
357a5617496SJie Yang 
35828ee563eSMyung Bae     dbus::utility::getAssociatedSubTreePaths(
359a5617496SJie Yang         chassisPath + "/containing",
36028ee563eSMyung Bae         sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0,
36128ee563eSMyung Bae         interfaces, std::bind_front(getChassisContains, asyncResp, chassisId));
362a5617496SJie Yang }
363a5617496SJie Yang 
364cf7eba09SNan Zhou /**
365cf7eba09SNan Zhou  * ChassisCollection derived class for delivering Chassis Collection Schema
366cf7eba09SNan Zhou  *  Functions triggers appropriate requests on DBus
367cf7eba09SNan Zhou  */
368cf7eba09SNan Zhou inline void requestRoutesChassisCollection(App& app)
369cf7eba09SNan Zhou {
370cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
371cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassisCollection)
372cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
373cf7eba09SNan Zhou             std::bind_front(handleChassisCollectionGet, std::ref(app)));
37462d5e2e4SEd Tanous }
375e37f8451SRapkiewicz, Pawel 
376bd79bce8SPatrick Williams inline void getChassisLocationCode(
377bd79bce8SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
378bd79bce8SPatrick Williams     const std::string& connectionName, const std::string& path)
379308f70c7SWilly Tu {
3801e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
3811e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
3821e1e598dSJonathan Doman         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
3835e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
3841e1e598dSJonathan Doman                     const std::string& property) {
385308f70c7SWilly Tu             if (ec)
386308f70c7SWilly Tu             {
38762598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for Location");
388308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
389308f70c7SWilly Tu                 return;
390308f70c7SWilly Tu             }
391308f70c7SWilly Tu 
392bd79bce8SPatrick Williams             asyncResp->res
393bd79bce8SPatrick Williams                 .jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
3941e1e598dSJonathan Doman                 property;
3951e1e598dSJonathan Doman         });
396308f70c7SWilly Tu }
397308f70c7SWilly Tu 
398308f70c7SWilly Tu inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
399308f70c7SWilly Tu                            const std::string& connectionName,
400308f70c7SWilly Tu                            const std::string& path)
401308f70c7SWilly Tu {
4021e1e598dSJonathan Doman     sdbusplus::asio::getProperty<std::string>(
4031e1e598dSJonathan Doman         *crow::connections::systemBus, connectionName, path,
4041e1e598dSJonathan Doman         "xyz.openbmc_project.Common.UUID", "UUID",
4055e7e2dc5SEd Tanous         [asyncResp](const boost::system::error_code& ec,
4061e1e598dSJonathan Doman                     const std::string& chassisUUID) {
407308f70c7SWilly Tu             if (ec)
408308f70c7SWilly Tu             {
40962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error for UUID");
410308f70c7SWilly Tu                 messages::internalError(asyncResp->res);
411308f70c7SWilly Tu                 return;
412308f70c7SWilly Tu             }
4131e1e598dSJonathan Doman             asyncResp->res.jsonValue["UUID"] = chassisUUID;
4141e1e598dSJonathan Doman         });
415308f70c7SWilly Tu }
416308f70c7SWilly Tu 
4177164bc62SChau Ly inline void handleDecoratorAssetProperties(
41845ca1b86SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4197164bc62SChau Ly     const std::string& chassisId, const std::string& path,
4207164bc62SChau Ly     const dbus::utility::DBusPropertiesMap& propertiesList)
421cf7eba09SNan Zhou {
4227164bc62SChau Ly     const std::string* partNumber = nullptr;
4237164bc62SChau Ly     const std::string* serialNumber = nullptr;
4247164bc62SChau Ly     const std::string* manufacturer = nullptr;
4257164bc62SChau Ly     const std::string* model = nullptr;
4267164bc62SChau Ly     const std::string* sparePartNumber = nullptr;
4277164bc62SChau Ly 
4287164bc62SChau Ly     const bool success = sdbusplus::unpackPropertiesNoThrow(
4297164bc62SChau Ly         dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
4307164bc62SChau Ly         partNumber, "SerialNumber", serialNumber, "Manufacturer", manufacturer,
4317164bc62SChau Ly         "Model", model, "SparePartNumber", sparePartNumber);
4327164bc62SChau Ly 
4337164bc62SChau Ly     if (!success)
43445ca1b86SEd Tanous     {
4357164bc62SChau Ly         messages::internalError(asyncResp->res);
43645ca1b86SEd Tanous         return;
43745ca1b86SEd Tanous     }
438734bfe90SGunnar Mills 
4397164bc62SChau Ly     if (partNumber != nullptr)
4407164bc62SChau Ly     {
4417164bc62SChau Ly         asyncResp->res.jsonValue["PartNumber"] = *partNumber;
4427164bc62SChau Ly     }
4437164bc62SChau Ly 
4447164bc62SChau Ly     if (serialNumber != nullptr)
4457164bc62SChau Ly     {
4467164bc62SChau Ly         asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
4477164bc62SChau Ly     }
4487164bc62SChau Ly 
4497164bc62SChau Ly     if (manufacturer != nullptr)
4507164bc62SChau Ly     {
4517164bc62SChau Ly         asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
4527164bc62SChau Ly     }
4537164bc62SChau Ly 
4547164bc62SChau Ly     if (model != nullptr)
4557164bc62SChau Ly     {
4567164bc62SChau Ly         asyncResp->res.jsonValue["Model"] = *model;
4577164bc62SChau Ly     }
4587164bc62SChau Ly 
4597164bc62SChau Ly     // SparePartNumber is optional on D-Bus
4607164bc62SChau Ly     // so skip if it is empty
4617164bc62SChau Ly     if (sparePartNumber != nullptr && !sparePartNumber->empty())
4627164bc62SChau Ly     {
4637164bc62SChau Ly         asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
4647164bc62SChau Ly     }
4657164bc62SChau Ly 
4667164bc62SChau Ly     asyncResp->res.jsonValue["Name"] = chassisId;
4677164bc62SChau Ly     asyncResp->res.jsonValue["Id"] = chassisId;
46825b54dbaSEd Tanous 
46925b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_POWER_THERMAL)
47025b54dbaSEd Tanous     {
4717164bc62SChau Ly         asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
4727164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Thermal", chassisId);
4737164bc62SChau Ly         // Power object
4747164bc62SChau Ly         asyncResp->res.jsonValue["Power"]["@odata.id"] =
4757164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Power", chassisId);
47625b54dbaSEd Tanous     }
47725b54dbaSEd Tanous 
47825b54dbaSEd Tanous     if constexpr (BMCWEB_REDFISH_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM)
47925b54dbaSEd Tanous     {
4807164bc62SChau Ly         asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
4817164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/ThermalSubsystem",
4827164bc62SChau Ly                                 chassisId);
4837164bc62SChau Ly         asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
48425b54dbaSEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
48525b54dbaSEd Tanous                                 chassisId);
4867164bc62SChau Ly         asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
4877164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/EnvironmentMetrics",
4887164bc62SChau Ly                                 chassisId);
48925b54dbaSEd Tanous     }
4907164bc62SChau Ly     // SensorCollection
4917164bc62SChau Ly     asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
4927164bc62SChau Ly         boost::urls::format("/redfish/v1/Chassis/{}/Sensors", chassisId);
493539d8c6bSEd Tanous     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
4947164bc62SChau Ly 
4957164bc62SChau Ly     nlohmann::json::array_t computerSystems;
4967164bc62SChau Ly     nlohmann::json::object_t system;
497bd79bce8SPatrick Williams     system["@odata.id"] =
498bd79bce8SPatrick Williams         std::format("/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
4997164bc62SChau Ly     computerSystems.emplace_back(std::move(system));
5007164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
5017164bc62SChau Ly         std::move(computerSystems);
5027164bc62SChau Ly 
5037164bc62SChau Ly     nlohmann::json::array_t managedBy;
5047164bc62SChau Ly     nlohmann::json::object_t manager;
505253f11b8SEd Tanous     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
506253f11b8SEd Tanous                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
5077164bc62SChau Ly     managedBy.emplace_back(std::move(manager));
5087164bc62SChau Ly     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
5097164bc62SChau Ly     getChassisState(asyncResp);
5107164bc62SChau Ly     getStorageLink(asyncResp, path);
5117164bc62SChau Ly }
5127164bc62SChau Ly 
513*2952f648SJoseph-Jonathan Salzano inline void handleChassisProperties(
514*2952f648SJoseph-Jonathan Salzano     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
515*2952f648SJoseph-Jonathan Salzano     const dbus::utility::DBusPropertiesMap& propertiesList)
516*2952f648SJoseph-Jonathan Salzano {
517*2952f648SJoseph-Jonathan Salzano     const std::string* type = nullptr;
518*2952f648SJoseph-Jonathan Salzano 
519*2952f648SJoseph-Jonathan Salzano     const bool success = sdbusplus::unpackPropertiesNoThrow(
520*2952f648SJoseph-Jonathan Salzano         dbus_utils::UnpackErrorPrinter(), propertiesList, "Type", type);
521*2952f648SJoseph-Jonathan Salzano 
522*2952f648SJoseph-Jonathan Salzano     if (!success)
523*2952f648SJoseph-Jonathan Salzano     {
524*2952f648SJoseph-Jonathan Salzano         messages::internalError(asyncResp->res);
525*2952f648SJoseph-Jonathan Salzano         return;
526*2952f648SJoseph-Jonathan Salzano     }
527*2952f648SJoseph-Jonathan Salzano 
528*2952f648SJoseph-Jonathan Salzano     if (type != nullptr)
529*2952f648SJoseph-Jonathan Salzano     {
530*2952f648SJoseph-Jonathan Salzano         auto chassisType = translateChassisTypeToRedfish(*type);
531*2952f648SJoseph-Jonathan Salzano         if (chassisType != chassis::ChassisType::Invalid)
532*2952f648SJoseph-Jonathan Salzano         {
533*2952f648SJoseph-Jonathan Salzano             asyncResp->res.jsonValue["ChassisType"] = chassisType;
534*2952f648SJoseph-Jonathan Salzano         }
535*2952f648SJoseph-Jonathan Salzano     }
536*2952f648SJoseph-Jonathan Salzano     else
537*2952f648SJoseph-Jonathan Salzano     {
538*2952f648SJoseph-Jonathan Salzano         asyncResp->res.jsonValue["ChassisType"] =
539*2952f648SJoseph-Jonathan Salzano             chassis::ChassisType::RackMount;
540*2952f648SJoseph-Jonathan Salzano     }
541*2952f648SJoseph-Jonathan Salzano }
542*2952f648SJoseph-Jonathan Salzano 
5437164bc62SChau Ly inline void handleChassisGetSubTree(
5447164bc62SChau Ly     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5457164bc62SChau Ly     const std::string& chassisId, const boost::system::error_code& ec,
5467164bc62SChau Ly     const dbus::utility::MapperGetSubTreeResponse& subtree)
5477164bc62SChau Ly {
54862d5e2e4SEd Tanous     if (ec)
5491abe55efSEd Tanous     {
55062598e31SEd Tanous         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
551f12894f8SJason M. Bills         messages::internalError(asyncResp->res);
552daf36e2eSEd Tanous         return;
553daf36e2eSEd Tanous     }
554daf36e2eSEd Tanous     // Iterate over all retrieved ObjectPaths.
555cf7eba09SNan Zhou     for (const std::pair<
556cf7eba09SNan Zhou              std::string,
557cf7eba09SNan Zhou              std::vector<std::pair<std::string, std::vector<std::string>>>>&
5581214b7e7SGunnar Mills              object : subtree)
5591abe55efSEd Tanous     {
560daf36e2eSEd Tanous         const std::string& path = object.first;
561cf7eba09SNan Zhou         const std::vector<std::pair<std::string, std::vector<std::string>>>&
5621214b7e7SGunnar Mills             connectionNames = object.second;
5637e860f15SJohn Edward Broadbent 
564997093ebSGeorge Liu         sdbusplus::message::object_path objPath(path);
565997093ebSGeorge Liu         if (objPath.filename() != chassisId)
5661abe55efSEd Tanous         {
567daf36e2eSEd Tanous             continue;
568daf36e2eSEd Tanous         }
56926f03899SShawn McCarney 
570a5617496SJie Yang         getChassisConnectivity(asyncResp, chassisId, path);
571a5617496SJie Yang 
57226f6976fSEd Tanous         if (connectionNames.empty())
5731abe55efSEd Tanous         {
57462598e31SEd Tanous             BMCWEB_LOG_ERROR("Got 0 Connection names");
575e0d918bcSEd Tanous             continue;
576daf36e2eSEd Tanous         }
577e0d918bcSEd Tanous 
5787164bc62SChau Ly         asyncResp->res.jsonValue["@odata.type"] = "#Chassis.v1_22_0.Chassis";
57949c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["@odata.id"] =
580ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
58149c53ac9SJohnathan Mantey         asyncResp->res.jsonValue["Name"] = "Chassis Collection";
582cf7eba09SNan Zhou         asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
5837164bc62SChau Ly             boost::urls::format("/redfish/v1/Chassis/{}/Actions/Chassis.Reset",
5847164bc62SChau Ly                                 chassisId);
5851476687dSEd Tanous         asyncResp->res
586cf7eba09SNan Zhou             .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
587ef4c65b7SEd Tanous             boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
588ef4c65b7SEd Tanous                                 chassisId);
5896c3e9451SGeorge Liu         dbus::utility::getAssociationEndPoints(
5906c3e9451SGeorge Liu             path + "/drive",
5917164bc62SChau Ly             [asyncResp, chassisId](const boost::system::error_code& ec3,
5926c3e9451SGeorge Liu                                    const dbus::utility::MapperEndPoints& resp) {
59392903bd4SJohn Edward Broadbent                 if (ec3 || resp.empty())
59492903bd4SJohn Edward Broadbent                 {
59592903bd4SJohn Edward Broadbent                     return; // no drives = no failures
59692903bd4SJohn Edward Broadbent                 }
59792903bd4SJohn Edward Broadbent 
59892903bd4SJohn Edward Broadbent                 nlohmann::json reference;
599bd79bce8SPatrick Williams                 reference["@odata.id"] = boost::urls::format(
600bd79bce8SPatrick Williams                     "/redfish/v1/Chassis/{}/Drives", chassisId);
60192903bd4SJohn Edward Broadbent                 asyncResp->res.jsonValue["Drives"] = std::move(reference);
60292903bd4SJohn Edward Broadbent             });
60392903bd4SJohn Edward Broadbent 
604002d39b4SEd Tanous         const std::string& connectionName = connectionNames[0].first;
6051c8fba97SJames Feist 
6067164bc62SChau Ly         const std::vector<std::string>& interfaces2 = connectionNames[0].second;
607e5ae9c1cSGeorge Liu         const std::array<const char*, 3> hasIndicatorLed = {
608e5ae9c1cSGeorge Liu             "xyz.openbmc_project.Inventory.Item.Chassis",
6091c8fba97SJames Feist             "xyz.openbmc_project.Inventory.Item.Panel",
6100fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
6111c8fba97SJames Feist 
612476b9cc5STejas Patil         const std::string assetTagInterface =
6130fda0f12SGeorge Liu             "xyz.openbmc_project.Inventory.Decorator.AssetTag";
614523d4868SLogananth Sundararaj         const std::string replaceableInterface =
615523d4868SLogananth Sundararaj             "xyz.openbmc_project.Inventory.Decorator.Replaceable";
616b4d593f1SCarson Labrado         const std::string revisionInterface =
617b4d593f1SCarson Labrado             "xyz.openbmc_project.Inventory.Decorator.Revision";
618523d4868SLogananth Sundararaj         for (const auto& interface : interfaces2)
619523d4868SLogananth Sundararaj         {
620523d4868SLogananth Sundararaj             if (interface == assetTagInterface)
621476b9cc5STejas Patil             {
6221e1e598dSJonathan Doman                 sdbusplus::asio::getProperty<std::string>(
623002d39b4SEd Tanous                     *crow::connections::systemBus, connectionName, path,
624002d39b4SEd Tanous                     assetTagInterface, "AssetTag",
6257164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
6261e1e598dSJonathan Doman                                            const std::string& property) {
6278a592810SEd Tanous                         if (ec2)
628476b9cc5STejas Patil                         {
629bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
630bd79bce8SPatrick Williams                                 "DBus response error for AssetTag: {}", ec2);
631476b9cc5STejas Patil                             messages::internalError(asyncResp->res);
632476b9cc5STejas Patil                             return;
633476b9cc5STejas Patil                         }
634002d39b4SEd Tanous                         asyncResp->res.jsonValue["AssetTag"] = property;
6351e1e598dSJonathan Doman                     });
636476b9cc5STejas Patil             }
637523d4868SLogananth Sundararaj             else if (interface == replaceableInterface)
638523d4868SLogananth Sundararaj             {
639523d4868SLogananth Sundararaj                 sdbusplus::asio::getProperty<bool>(
640523d4868SLogananth Sundararaj                     *crow::connections::systemBus, connectionName, path,
641523d4868SLogananth Sundararaj                     replaceableInterface, "HotPluggable",
6427164bc62SChau Ly                     [asyncResp, chassisId](const boost::system::error_code& ec2,
643523d4868SLogananth Sundararaj                                            const bool property) {
644523d4868SLogananth Sundararaj                         if (ec2)
645523d4868SLogananth Sundararaj                         {
64662598e31SEd Tanous                             BMCWEB_LOG_ERROR(
647bd79bce8SPatrick Williams                                 "DBus response error for HotPluggable: {}",
648bd79bce8SPatrick Williams                                 ec2);
649523d4868SLogananth Sundararaj                             messages::internalError(asyncResp->res);
650523d4868SLogananth Sundararaj                             return;
651523d4868SLogananth Sundararaj                         }
652523d4868SLogananth Sundararaj                         asyncResp->res.jsonValue["HotPluggable"] = property;
653523d4868SLogananth Sundararaj                     });
654523d4868SLogananth Sundararaj             }
655b4d593f1SCarson Labrado             else if (interface == revisionInterface)
656b4d593f1SCarson Labrado             {
657b4d593f1SCarson Labrado                 sdbusplus::asio::getProperty<std::string>(
658b4d593f1SCarson Labrado                     *crow::connections::systemBus, connectionName, path,
659b4d593f1SCarson Labrado                     revisionInterface, "Version",
660b4d593f1SCarson Labrado                     [asyncResp, chassisId](const boost::system::error_code& ec2,
661b4d593f1SCarson Labrado                                            const std::string& property) {
662b4d593f1SCarson Labrado                         if (ec2)
663b4d593f1SCarson Labrado                         {
664bd79bce8SPatrick Williams                             BMCWEB_LOG_ERROR(
665bd79bce8SPatrick Williams                                 "DBus response error for Version: {}", ec2);
666b4d593f1SCarson Labrado                             messages::internalError(asyncResp->res);
667b4d593f1SCarson Labrado                             return;
668b4d593f1SCarson Labrado                         }
669b4d593f1SCarson Labrado                         asyncResp->res.jsonValue["Version"] = property;
670b4d593f1SCarson Labrado                     });
671b4d593f1SCarson Labrado             }
672523d4868SLogananth Sundararaj         }
673476b9cc5STejas Patil 
6741c8fba97SJames Feist         for (const char* interface : hasIndicatorLed)
6751c8fba97SJames Feist         {
6767164bc62SChau Ly             if (std::ranges::find(interfaces2, interface) != interfaces2.end())
6771c8fba97SJames Feist             {
6781c8fba97SJames Feist                 getIndicatorLedState(asyncResp);
67959a17e4fSGeorge Liu                 getSystemLocationIndicatorActive(asyncResp);
6801c8fba97SJames Feist                 break;
6811c8fba97SJames Feist             }
6821c8fba97SJames Feist         }
6831c8fba97SJames Feist 
68486d89ed7SKrzysztof Grobelny         sdbusplus::asio::getAllProperties(
68586d89ed7SKrzysztof Grobelny             *crow::connections::systemBus, connectionName, path,
68686d89ed7SKrzysztof Grobelny             "xyz.openbmc_project.Inventory.Decorator.Asset",
6877164bc62SChau Ly             [asyncResp, chassisId,
6887164bc62SChau Ly              path](const boost::system::error_code&,
689cf7eba09SNan Zhou                    const dbus::utility::DBusPropertiesMap& propertiesList) {
6907164bc62SChau Ly                 handleDecoratorAssetProperties(asyncResp, chassisId, path,
6917164bc62SChau Ly                                                propertiesList);
69286d89ed7SKrzysztof Grobelny             });
6932c37b4b0SSharad Yadav 
694*2952f648SJoseph-Jonathan Salzano         sdbusplus::asio::getAllProperties(
695*2952f648SJoseph-Jonathan Salzano             *crow::connections::systemBus, connectionName, path,
696*2952f648SJoseph-Jonathan Salzano             "xyz.openbmc_project.Inventory.Item.Chassis",
697*2952f648SJoseph-Jonathan Salzano             [asyncResp](
698*2952f648SJoseph-Jonathan Salzano                 const boost::system::error_code&,
699*2952f648SJoseph-Jonathan Salzano                 const dbus::utility::DBusPropertiesMap& propertiesList) {
700*2952f648SJoseph-Jonathan Salzano                 handleChassisProperties(asyncResp, propertiesList);
701*2952f648SJoseph-Jonathan Salzano             });
702*2952f648SJoseph-Jonathan Salzano 
703308f70c7SWilly Tu         for (const auto& interface : interfaces2)
7042c37b4b0SSharad Yadav         {
705308f70c7SWilly Tu             if (interface == "xyz.openbmc_project.Common.UUID")
7062c37b4b0SSharad Yadav             {
707308f70c7SWilly Tu                 getChassisUUID(asyncResp, connectionName, path);
7082c37b4b0SSharad Yadav             }
709cf7eba09SNan Zhou             else if (interface ==
7100fda0f12SGeorge Liu                      "xyz.openbmc_project.Inventory.Decorator.LocationCode")
7112c37b4b0SSharad Yadav             {
712002d39b4SEd Tanous                 getChassisLocationCode(asyncResp, connectionName, path);
7132c37b4b0SSharad Yadav             }
7142c37b4b0SSharad Yadav         }
7152c37b4b0SSharad Yadav 
716daf36e2eSEd Tanous         return;
717daf36e2eSEd Tanous     }
718e0d918bcSEd Tanous 
719daf36e2eSEd Tanous     // Couldn't find an object with that name.  return an error
720d8a5d5d8SJiaqing Zhao     messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
7217164bc62SChau Ly }
722c181942fSQiang XU 
7237164bc62SChau Ly inline void
7247164bc62SChau Ly     handleChassisGet(App& app, const crow::Request& req,
7257164bc62SChau Ly                      const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7267164bc62SChau Ly                      const std::string& chassisId)
7277164bc62SChau Ly {
7287164bc62SChau Ly     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
7297164bc62SChau Ly     {
7307164bc62SChau Ly         return;
7317164bc62SChau Ly     }
7327164bc62SChau Ly     constexpr std::array<std::string_view, 2> interfaces = {
7337164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Board",
7347164bc62SChau Ly         "xyz.openbmc_project.Inventory.Item.Chassis"};
7357164bc62SChau Ly 
7367164bc62SChau Ly     dbus::utility::getSubTree(
7377164bc62SChau Ly         "/xyz/openbmc_project/inventory", 0, interfaces,
7387164bc62SChau Ly         std::bind_front(handleChassisGetSubTree, asyncResp, chassisId));
7397164bc62SChau Ly 
7407164bc62SChau Ly     constexpr std::array<std::string_view, 1> interfaces2 = {
7417164bc62SChau Ly         "xyz.openbmc_project.Chassis.Intrusion"};
7427164bc62SChau Ly 
7437164bc62SChau Ly     dbus::utility::getSubTree(
7447164bc62SChau Ly         "/xyz/openbmc_project", 0, interfaces2,
7457164bc62SChau Ly         std::bind_front(handlePhysicalSecurityGetSubTree, asyncResp));
746cf7eba09SNan Zhou }
7471c8fba97SJames Feist 
748cf7eba09SNan Zhou inline void
749cf7eba09SNan Zhou     handleChassisPatch(App& app, const crow::Request& req,
7507e860f15SJohn Edward Broadbent                        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
751cf7eba09SNan Zhou                        const std::string& param)
752cf7eba09SNan Zhou {
7533ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75445ca1b86SEd Tanous     {
75545ca1b86SEd Tanous         return;
75645ca1b86SEd Tanous     }
7579f8bfa7cSGunnar Mills     std::optional<bool> locationIndicatorActive;
7581c8fba97SJames Feist     std::optional<std::string> indicatorLed;
7591c8fba97SJames Feist 
7607e860f15SJohn Edward Broadbent     if (param.empty())
7611c8fba97SJames Feist     {
7621c8fba97SJames Feist         return;
7631c8fba97SJames Feist     }
7641c8fba97SJames Feist 
765afc474aeSMyung Bae     if (!json_util::readJsonPatch( //
766afc474aeSMyung Bae             req, asyncResp->res, //
767afc474aeSMyung Bae             "IndicatorLED", indicatorLed, //
768afc474aeSMyung Bae             "LocationIndicatorActive", locationIndicatorActive //
769afc474aeSMyung Bae             ))
7701c8fba97SJames Feist     {
7711c8fba97SJames Feist         return;
7721c8fba97SJames Feist     }
7731c8fba97SJames Feist 
7749f8bfa7cSGunnar Mills     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
7759f8bfa7cSGunnar Mills     if (!locationIndicatorActive && !indicatorLed)
7761c8fba97SJames Feist     {
7771c8fba97SJames Feist         return; // delete this when we support more patch properties
7781c8fba97SJames Feist     }
779d6aa0093SGunnar Mills     if (indicatorLed)
780d6aa0093SGunnar Mills     {
7817e860f15SJohn Edward Broadbent         asyncResp->res.addHeader(
7827e860f15SJohn Edward Broadbent             boost::beast::http::field::warning,
7830fda0f12SGeorge Liu             "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
784d6aa0093SGunnar Mills     }
7851c8fba97SJames Feist 
786e99073f5SGeorge Liu     constexpr std::array<std::string_view, 2> interfaces = {
7871c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Board",
7881c8fba97SJames Feist         "xyz.openbmc_project.Inventory.Item.Chassis"};
7891c8fba97SJames Feist 
7907e860f15SJohn Edward Broadbent     const std::string& chassisId = param;
7911c8fba97SJames Feist 
792e99073f5SGeorge Liu     dbus::utility::getSubTree(
793e99073f5SGeorge Liu         "/xyz/openbmc_project/inventory", 0, interfaces,
794cf7eba09SNan Zhou         [asyncResp, chassisId, locationIndicatorActive,
7955e7e2dc5SEd Tanous          indicatorLed](const boost::system::error_code& ec,
796b9d36b47SEd Tanous                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
7971c8fba97SJames Feist             if (ec)
7981c8fba97SJames Feist             {
79962598e31SEd Tanous                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
8001c8fba97SJames Feist                 messages::internalError(asyncResp->res);
8011c8fba97SJames Feist                 return;
8021c8fba97SJames Feist             }
8031c8fba97SJames Feist 
8041c8fba97SJames Feist             // Iterate over all retrieved ObjectPaths.
805bd79bce8SPatrick Williams             for (const std::pair<std::string,
806bd79bce8SPatrick Williams                                  std::vector<std::pair<
807bd79bce8SPatrick Williams                                      std::string, std::vector<std::string>>>>&
8081214b7e7SGunnar Mills                      object : subtree)
8091c8fba97SJames Feist             {
8101c8fba97SJames Feist                 const std::string& path = object.first;
811bd79bce8SPatrick Williams                 const std::vector<
812bd79bce8SPatrick Williams                     std::pair<std::string, std::vector<std::string>>>&
8131214b7e7SGunnar Mills                     connectionNames = object.second;
8141c8fba97SJames Feist 
815997093ebSGeorge Liu                 sdbusplus::message::object_path objPath(path);
816997093ebSGeorge Liu                 if (objPath.filename() != chassisId)
8171c8fba97SJames Feist                 {
8181c8fba97SJames Feist                     continue;
8191c8fba97SJames Feist                 }
8201c8fba97SJames Feist 
82126f6976fSEd Tanous                 if (connectionNames.empty())
8221c8fba97SJames Feist                 {
82362598e31SEd Tanous                     BMCWEB_LOG_ERROR("Got 0 Connection names");
8241c8fba97SJames Feist                     continue;
8251c8fba97SJames Feist                 }
8261c8fba97SJames Feist 
82723a21a1cSEd Tanous                 const std::vector<std::string>& interfaces3 =
8281c8fba97SJames Feist                     connectionNames[0].second;
8291c8fba97SJames Feist 
830e5ae9c1cSGeorge Liu                 const std::array<const char*, 3> hasIndicatorLed = {
831e5ae9c1cSGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Chassis",
8321c8fba97SJames Feist                     "xyz.openbmc_project.Inventory.Item.Panel",
8330fda0f12SGeorge Liu                     "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
8341c8fba97SJames Feist                 bool indicatorChassis = false;
8351c8fba97SJames Feist                 for (const char* interface : hasIndicatorLed)
8361c8fba97SJames Feist                 {
8373544d2a7SEd Tanous                     if (std::ranges::find(interfaces3, interface) !=
8383544d2a7SEd Tanous                         interfaces3.end())
8391c8fba97SJames Feist                     {
8401c8fba97SJames Feist                         indicatorChassis = true;
8411c8fba97SJames Feist                         break;
8421c8fba97SJames Feist                     }
8431c8fba97SJames Feist                 }
8449f8bfa7cSGunnar Mills                 if (locationIndicatorActive)
8459f8bfa7cSGunnar Mills                 {
8469f8bfa7cSGunnar Mills                     if (indicatorChassis)
8479f8bfa7cSGunnar Mills                     {
848bd79bce8SPatrick Williams                         setSystemLocationIndicatorActive(
849bd79bce8SPatrick Williams                             asyncResp, *locationIndicatorActive);
8509f8bfa7cSGunnar Mills                     }
8519f8bfa7cSGunnar Mills                     else
8529f8bfa7cSGunnar Mills                     {
853002d39b4SEd Tanous                         messages::propertyUnknown(asyncResp->res,
854002d39b4SEd Tanous                                                   "LocationIndicatorActive");
8559f8bfa7cSGunnar Mills                     }
8569f8bfa7cSGunnar Mills                 }
8579f8bfa7cSGunnar Mills                 if (indicatorLed)
8589f8bfa7cSGunnar Mills                 {
8591c8fba97SJames Feist                     if (indicatorChassis)
8601c8fba97SJames Feist                     {
861f23b7296SEd Tanous                         setIndicatorLedState(asyncResp, *indicatorLed);
8621c8fba97SJames Feist                     }
8631c8fba97SJames Feist                     else
8641c8fba97SJames Feist                     {
865bd79bce8SPatrick Williams                         messages::propertyUnknown(asyncResp->res,
866bd79bce8SPatrick Williams                                                   "IndicatorLED");
8671c8fba97SJames Feist                     }
8681c8fba97SJames Feist                 }
8691c8fba97SJames Feist                 return;
8701c8fba97SJames Feist             }
8711c8fba97SJames Feist 
872d8a5d5d8SJiaqing Zhao             messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
873e99073f5SGeorge Liu         });
874cf7eba09SNan Zhou }
875cf7eba09SNan Zhou 
876cf7eba09SNan Zhou /**
877cf7eba09SNan Zhou  * Chassis override class for delivering Chassis Schema
878cf7eba09SNan Zhou  * Functions triggers appropriate requests on DBus
879cf7eba09SNan Zhou  */
880cf7eba09SNan Zhou inline void requestRoutesChassis(App& app)
881cf7eba09SNan Zhou {
882cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
883cf7eba09SNan Zhou         .privileges(redfish::privileges::getChassis)
884cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
885cf7eba09SNan Zhou             std::bind_front(handleChassisGet, std::ref(app)));
886cf7eba09SNan Zhou 
887cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
888cf7eba09SNan Zhou         .privileges(redfish::privileges::patchChassis)
889cf7eba09SNan Zhou         .methods(boost::beast::http::verb::patch)(
890cf7eba09SNan Zhou             std::bind_front(handleChassisPatch, std::ref(app)));
8911c8fba97SJames Feist }
892dd99e04bSP.K. Lee 
8938d1b46d7Szhanghch05 inline void
8948d1b46d7Szhanghch05     doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
895dd99e04bSP.K. Lee {
8967a1dbc48SGeorge Liu     constexpr std::array<std::string_view, 1> interfaces = {
897c3b3c92aSVijay Khemka         "xyz.openbmc_project.State.Chassis"};
898c3b3c92aSVijay Khemka 
899c3b3c92aSVijay Khemka     // Use mapper to get subtree paths.
9007a1dbc48SGeorge Liu     dbus::utility::getSubTreePaths(
9017a1dbc48SGeorge Liu         "/", 0, interfaces,
902b9d36b47SEd Tanous         [asyncResp](
9037a1dbc48SGeorge Liu             const boost::system::error_code& ec,
904b9d36b47SEd Tanous             const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
905c3b3c92aSVijay Khemka             if (ec)
906c3b3c92aSVijay Khemka             {
90762598e31SEd Tanous                 BMCWEB_LOG_ERROR("[mapper] Bad D-Bus request error: {}", ec);
908c3b3c92aSVijay Khemka                 messages::internalError(asyncResp->res);
909c3b3c92aSVijay Khemka                 return;
910c3b3c92aSVijay Khemka             }
911c3b3c92aSVijay Khemka 
912dd99e04bSP.K. Lee             const char* processName = "xyz.openbmc_project.State.Chassis";
913dd99e04bSP.K. Lee             const char* interfaceName = "xyz.openbmc_project.State.Chassis";
914dd99e04bSP.K. Lee             const char* destProperty = "RequestedPowerTransition";
915dd99e04bSP.K. Lee             const std::string propertyValue =
916dd99e04bSP.K. Lee                 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
917bd79bce8SPatrick Williams             std::string objectPath =
918bd79bce8SPatrick Williams                 "/xyz/openbmc_project/state/chassis_system0";
919c3b3c92aSVijay Khemka 
920c3b3c92aSVijay Khemka             /* Look for system reset chassis path */
921bd79bce8SPatrick Williams             if ((std::ranges::find(chassisList, objectPath)) ==
922bd79bce8SPatrick Williams                 chassisList.end())
923c3b3c92aSVijay Khemka             {
924c3b3c92aSVijay Khemka                 /* We prefer to reset the full chassis_system, but if it doesn't
925c3b3c92aSVijay Khemka                  * exist on some platforms, fall back to a host-only power reset
926c3b3c92aSVijay Khemka                  */
927c3b3c92aSVijay Khemka                 objectPath = "/xyz/openbmc_project/state/chassis0";
928c3b3c92aSVijay Khemka             }
929dd99e04bSP.K. Lee 
930e93abac6SGinu George             setDbusProperty(asyncResp, "ResetType", processName, objectPath,
931e93abac6SGinu George                             interfaceName, destProperty, propertyValue);
9327a1dbc48SGeorge Liu         });
933dd99e04bSP.K. Lee }
934dd99e04bSP.K. Lee 
935cf7eba09SNan Zhou inline void handleChassisResetActionInfoPost(
936cf7eba09SNan Zhou     App& app, const crow::Request& req,
9377e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
938cf7eba09SNan Zhou     const std::string& /*chassisId*/)
939cf7eba09SNan Zhou {
9403ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
94145ca1b86SEd Tanous     {
94245ca1b86SEd Tanous         return;
94345ca1b86SEd Tanous     }
94462598e31SEd Tanous     BMCWEB_LOG_DEBUG("Post Chassis Reset.");
945dd99e04bSP.K. Lee 
946dd99e04bSP.K. Lee     std::string resetType;
947dd99e04bSP.K. Lee 
948cf7eba09SNan Zhou     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
949dd99e04bSP.K. Lee     {
950dd99e04bSP.K. Lee         return;
951dd99e04bSP.K. Lee     }
952dd99e04bSP.K. Lee 
953dd99e04bSP.K. Lee     if (resetType != "PowerCycle")
954dd99e04bSP.K. Lee     {
95562598e31SEd Tanous         BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType);
956002d39b4SEd Tanous         messages::actionParameterNotSupported(asyncResp->res, resetType,
957002d39b4SEd Tanous                                               "ResetType");
958dd99e04bSP.K. Lee 
959dd99e04bSP.K. Lee         return;
960dd99e04bSP.K. Lee     }
961dd99e04bSP.K. Lee     doChassisPowerCycle(asyncResp);
962dd99e04bSP.K. Lee }
9631cb1a9e6SAppaRao Puli 
9641cb1a9e6SAppaRao Puli /**
965cf7eba09SNan Zhou  * ChassisResetAction class supports the POST method for the Reset
966cf7eba09SNan Zhou  * action.
967cf7eba09SNan Zhou  * Function handles POST method request.
968cf7eba09SNan Zhou  * Analyzes POST body before sending Reset request data to D-Bus.
9691cb1a9e6SAppaRao Puli  */
970cf7eba09SNan Zhou 
971cf7eba09SNan Zhou inline void requestRoutesChassisResetAction(App& app)
9721cb1a9e6SAppaRao Puli {
973cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
974cf7eba09SNan Zhou         .privileges(redfish::privileges::postChassis)
975cf7eba09SNan Zhou         .methods(boost::beast::http::verb::post)(
976cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
977cf7eba09SNan Zhou }
978cf7eba09SNan Zhou 
979cf7eba09SNan Zhou inline void handleChassisResetActionInfoGet(
980cf7eba09SNan Zhou     App& app, const crow::Request& req,
9817e860f15SJohn Edward Broadbent     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
982cf7eba09SNan Zhou     const std::string& chassisId)
983cf7eba09SNan Zhou {
9843ba00073SCarson Labrado     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
9851cb1a9e6SAppaRao Puli     {
98645ca1b86SEd Tanous         return;
98745ca1b86SEd Tanous     }
988cf7eba09SNan Zhou     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
989ef4c65b7SEd Tanous     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
990ef4c65b7SEd Tanous         "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
9911476687dSEd Tanous     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
9921476687dSEd Tanous 
9931476687dSEd Tanous     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
9945b9e95a1SNan Zhou     nlohmann::json::array_t parameters;
9955b9e95a1SNan Zhou     nlohmann::json::object_t parameter;
9965b9e95a1SNan Zhou     parameter["Name"] = "ResetType";
9975b9e95a1SNan Zhou     parameter["Required"] = true;
998539d8c6bSEd Tanous     parameter["DataType"] = action_info::ParameterTypes::String;
9991476687dSEd Tanous     nlohmann::json::array_t allowed;
1000ad539545SPatrick Williams     allowed.emplace_back("PowerCycle");
10015b9e95a1SNan Zhou     parameter["AllowableValues"] = std::move(allowed);
1002ad539545SPatrick Williams     parameters.emplace_back(std::move(parameter));
10035b9e95a1SNan Zhou 
10041476687dSEd Tanous     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
1005cf7eba09SNan Zhou }
1006cf7eba09SNan Zhou 
1007cf7eba09SNan Zhou /**
1008cf7eba09SNan Zhou  * ChassisResetActionInfo derived class for delivering Chassis
1009cf7eba09SNan Zhou  * ResetType AllowableValues using ResetInfo schema.
1010cf7eba09SNan Zhou  */
1011cf7eba09SNan Zhou inline void requestRoutesChassisResetActionInfo(App& app)
1012cf7eba09SNan Zhou {
1013cf7eba09SNan Zhou     BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
1014cf7eba09SNan Zhou         .privileges(redfish::privileges::getActionInfo)
1015cf7eba09SNan Zhou         .methods(boost::beast::http::verb::get)(
1016cf7eba09SNan Zhou             std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
10171cb1a9e6SAppaRao Puli }
10181cb1a9e6SAppaRao Puli 
1019e37f8451SRapkiewicz, Pawel } // namespace redfish
1020