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