blob: c6016cbe12e67c7cc8e1d9f4cd21dfca9df40fd5 [file] [log] [blame]
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
James Feistb49ac872019-05-21 15:12:01 -070018#include "health.hpp"
James Feist1c8fba92019-12-20 15:12:07 -080019#include "led.hpp"
Nan Zhoucf7eba02022-07-21 23:53:20 +000020#include "utils/json_utils.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070021
John Edward Broadbent7e860f12021-04-08 15:57:16 -070022#include <app.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080023#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070024#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070025#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070026#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020027#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills02f6ff12020-10-14 15:59:58 -050028#include <utils/collection.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020029#include <utils/dbus_utils.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050030
Ed Tanous1abe55e2018-09-05 08:30:59 -070031namespace redfish
32{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010033
34/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060035 * @brief Retrieves chassis state properties over dbus
36 *
37 * @param[in] aResp - Shared pointer for completing asynchronous calls.
38 *
39 * @return None.
40 */
zhanghch058d1b46d2021-04-01 11:18:24 +080041inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060042{
Jonathan Doman1e1e5982021-06-11 09:36:17 -070043 // crow::connections::systemBus->async_method_call(
44 sdbusplus::asio::getProperty<std::string>(
45 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
46 "/xyz/openbmc_project/state/chassis0",
47 "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
48 [aResp{std::move(aResp)}](const boost::system::error_code ec,
49 const std::string& chassisState) {
Ed Tanous002d39b2022-05-31 08:59:27 -070050 if (ec)
51 {
52 if (ec == boost::system::errc::host_unreachable)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060053 {
Ed Tanous002d39b2022-05-31 08:59:27 -070054 // Service not available, no error, just don't return
55 // chassis state info
56 BMCWEB_LOG_DEBUG << "Service not available " << ec;
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060057 return;
58 }
Ed Tanous002d39b2022-05-31 08:59:27 -070059 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
60 messages::internalError(aResp->res);
61 return;
62 }
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060063
Ed Tanous002d39b2022-05-31 08:59:27 -070064 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
65 // Verify Chassis State
66 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
67 {
68 aResp->res.jsonValue["PowerState"] = "On";
69 aResp->res.jsonValue["Status"]["State"] = "Enabled";
70 }
71 else if (chassisState ==
72 "xyz.openbmc_project.State.Chassis.PowerState.Off")
73 {
74 aResp->res.jsonValue["PowerState"] = "Off";
75 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
76 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070077 });
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060078}
79
zhanghch058d1b46d2021-04-01 11:18:24 +080080inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Ed Tanous23a21a12020-07-25 04:45:05 +000081 const std::string& service,
82 const std::string& objPath)
Qiang XUc1819422019-02-27 13:51:32 +080083{
84 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
85
Jonathan Doman1e1e5982021-06-11 09:36:17 -070086 sdbusplus::asio::getProperty<std::string>(
87 *crow::connections::systemBus, service, objPath,
88 "xyz.openbmc_project.Chassis.Intrusion", "Status",
Qiang XUc1819422019-02-27 13:51:32 +080089 [aResp{std::move(aResp)}](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070090 const std::string& value) {
Ed Tanous002d39b2022-05-31 08:59:27 -070091 if (ec)
92 {
93 // do not add err msg in redfish response, because this is not
94 // mandatory property
95 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
96 return;
97 }
Qiang XUc1819422019-02-27 13:51:32 +080098
Ed Tanous002d39b2022-05-31 08:59:27 -070099 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
100 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700101 });
Qiang XUc1819422019-02-27 13:51:32 +0800102}
103
104/**
105 * Retrieves physical security properties over dbus
106 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800107inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp)
Qiang XUc1819422019-02-27 13:51:32 +0800108{
109 crow::connections::systemBus->async_method_call(
110 [aResp{std::move(aResp)}](
111 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800112 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700113 if (ec)
114 {
115 // do not add err msg in redfish response, because this is not
116 // mandatory property
117 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
118 return;
119 }
120 // Iterate over all retrieved ObjectPaths.
121 for (const auto& object : subtree)
122 {
123 for (const auto& service : object.second)
Qiang XUc1819422019-02-27 13:51:32 +0800124 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 getIntrusionByService(aResp, service.first, object.first);
Qiang XUc1819422019-02-27 13:51:32 +0800126 return;
127 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700128 }
Qiang XUc1819422019-02-27 13:51:32 +0800129 },
130 "xyz.openbmc_project.ObjectMapper",
131 "/xyz/openbmc_project/object_mapper",
132 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700133 "/xyz/openbmc_project/Intrusion", 1,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500134 std::array<const char*, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
Qiang XUc1819422019-02-27 13:51:32 +0800135}
136
Nan Zhoucf7eba02022-07-21 23:53:20 +0000137inline void handleChassisCollectionGet(
138 App& app, const crow::Request& req,
139 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
140{
141 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
142 {
143 return;
144 }
145 asyncResp->res.jsonValue["@odata.type"] =
146 "#ChassisCollection.ChassisCollection";
147 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
148 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
149
150 collection_util::getCollectionMembers(
Willy Tuae9031f2022-09-27 05:48:07 +0000151 asyncResp, boost::urls::url("/redfish/v1/Chassis"),
Nan Zhoucf7eba02022-07-21 23:53:20 +0000152 {"xyz.openbmc_project.Inventory.Item.Board",
153 "xyz.openbmc_project.Inventory.Item.Chassis"});
154}
155
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100156/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100157 * ChassisCollection derived class for delivering Chassis Collection Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700158 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100159 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700160inline void requestRoutesChassisCollection(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700161{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700162 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
Ed Tanoused398212021-06-09 17:05:54 -0700163 .privileges(redfish::privileges::getChassisCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700164 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000165 std::bind_front(handleChassisCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700166}
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100167
Willy Tu308f70c2021-09-28 20:24:52 -0700168inline void
169 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
170 const std::string& connectionName,
171 const std::string& path)
172{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700173 sdbusplus::asio::getProperty<std::string>(
174 *crow::connections::systemBus, connectionName, path,
175 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Willy Tu308f70c2021-09-28 20:24:52 -0700176 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700177 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 if (ec)
179 {
180 BMCWEB_LOG_DEBUG << "DBUS response error for Location";
181 messages::internalError(asyncResp->res);
182 return;
183 }
Willy Tu308f70c2021-09-28 20:24:52 -0700184
Ed Tanous002d39b2022-05-31 08:59:27 -0700185 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
186 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700187 });
Willy Tu308f70c2021-09-28 20:24:52 -0700188}
189
190inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191 const std::string& connectionName,
192 const std::string& path)
193{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700194 sdbusplus::asio::getProperty<std::string>(
195 *crow::connections::systemBus, connectionName, path,
196 "xyz.openbmc_project.Common.UUID", "UUID",
Willy Tu308f70c2021-09-28 20:24:52 -0700197 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700198 const std::string& chassisUUID) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700199 if (ec)
200 {
201 BMCWEB_LOG_DEBUG << "DBUS response error for UUID";
202 messages::internalError(asyncResp->res);
203 return;
204 }
205 asyncResp->res.jsonValue["UUID"] = chassisUUID;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700206 });
Willy Tu308f70c2021-09-28 20:24:52 -0700207}
208
Nan Zhoucf7eba02022-07-21 23:53:20 +0000209inline void
210 handleChassisGet(App& app, const crow::Request& req,
211 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
212 const std::string& chassisId)
213{
214 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
215 {
216 return;
217 }
218 const std::array<const char*, 2> interfaces = {
219 "xyz.openbmc_project.Inventory.Item.Board",
220 "xyz.openbmc_project.Inventory.Item.Chassis"};
221
222 crow::connections::systemBus->async_method_call(
223 [asyncResp, chassisId(std::string(chassisId))](
224 const boost::system::error_code ec,
225 const dbus::utility::MapperGetSubTreeResponse& subtree) {
226 if (ec)
227 {
228 messages::internalError(asyncResp->res);
229 return;
230 }
231 // Iterate over all retrieved ObjectPaths.
232 for (const std::pair<
233 std::string,
234 std::vector<std::pair<std::string, std::vector<std::string>>>>&
235 object : subtree)
236 {
237 const std::string& path = object.first;
238 const std::vector<std::pair<std::string, std::vector<std::string>>>&
239 connectionNames = object.second;
240
241 sdbusplus::message::object_path objPath(path);
242 if (objPath.filename() != chassisId)
243 {
244 continue;
245 }
246
247 auto health = std::make_shared<HealthPopulate>(asyncResp);
248
249 sdbusplus::asio::getProperty<std::vector<std::string>>(
250 *crow::connections::systemBus,
251 "xyz.openbmc_project.ObjectMapper", path + "/all_sensors",
252 "xyz.openbmc_project.Association", "endpoints",
253 [health](const boost::system::error_code ec2,
254 const std::vector<std::string>& resp) {
255 if (ec2)
256 {
257 return; // no sensors = no failures
258 }
259 health->inventory = resp;
260 });
261
262 health->populate();
263
264 if (connectionNames.empty())
265 {
266 BMCWEB_LOG_ERROR << "Got 0 Connection names";
267 continue;
268 }
269
270 asyncResp->res.jsonValue["@odata.type"] =
271 "#Chassis.v1_16_0.Chassis";
272 asyncResp->res.jsonValue["@odata.id"] =
273 "/redfish/v1/Chassis/" + chassisId;
274 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
275 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
276 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
277 "/redfish/v1/Chassis/" + chassisId + "/Actions/Chassis.Reset";
278 asyncResp->res
279 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
280 "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
281 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
282 "/redfish/v1/Systems/system/PCIeDevices";
283
284 sdbusplus::asio::getProperty<std::vector<std::string>>(
285 *crow::connections::systemBus,
286 "xyz.openbmc_project.ObjectMapper", path + "/drive",
287 "xyz.openbmc_project.Association", "endpoints",
288 [asyncResp, chassisId](const boost::system::error_code ec3,
289 const std::vector<std::string>& resp) {
290 if (ec3 || resp.empty())
291 {
292 return; // no drives = no failures
293 }
294
295 nlohmann::json reference;
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700296 reference["@odata.id"] = crow::utility::urlFromPieces(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000297 "redfish", "v1", "Chassis", chassisId, "Drives");
298 asyncResp->res.jsonValue["Drives"] = std::move(reference);
299 });
300
301 const std::string& connectionName = connectionNames[0].first;
302
303 const std::vector<std::string>& interfaces2 =
304 connectionNames[0].second;
305 const std::array<const char*, 2> hasIndicatorLed = {
306 "xyz.openbmc_project.Inventory.Item.Panel",
307 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
308
309 const std::string assetTagInterface =
310 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
311 if (std::find(interfaces2.begin(), interfaces2.end(),
312 assetTagInterface) != interfaces2.end())
313 {
314 sdbusplus::asio::getProperty<std::string>(
315 *crow::connections::systemBus, connectionName, path,
316 assetTagInterface, "AssetTag",
317 [asyncResp, chassisId(std::string(chassisId))](
318 const boost::system::error_code ec2,
319 const std::string& property) {
320 if (ec2)
321 {
322 BMCWEB_LOG_DEBUG << "DBus response error for AssetTag";
323 messages::internalError(asyncResp->res);
324 return;
325 }
326 asyncResp->res.jsonValue["AssetTag"] = property;
327 });
328 }
329
330 for (const char* interface : hasIndicatorLed)
331 {
332 if (std::find(interfaces2.begin(), interfaces2.end(),
333 interface) != interfaces2.end())
334 {
335 getIndicatorLedState(asyncResp);
336 getLocationIndicatorActive(asyncResp);
337 break;
338 }
339 }
340
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200341 sdbusplus::asio::getAllProperties(
342 *crow::connections::systemBus, connectionName, path,
343 "xyz.openbmc_project.Inventory.Decorator.Asset",
Nan Zhoucf7eba02022-07-21 23:53:20 +0000344 [asyncResp, chassisId(std::string(chassisId))](
345 const boost::system::error_code /*ec2*/,
346 const dbus::utility::DBusPropertiesMap& propertiesList) {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200347 const std::string* partNumber = nullptr;
348 const std::string* serialNumber = nullptr;
349 const std::string* manufacturer = nullptr;
350 const std::string* model = nullptr;
351 const std::string* sparePartNumber = nullptr;
352
353 const bool success = sdbusplus::unpackPropertiesNoThrow(
354 dbus_utils::UnpackErrorPrinter(), propertiesList,
355 "PartNumber", partNumber, "SerialNumber", serialNumber,
356 "Manufacturer", manufacturer, "Model", model,
357 "SparePartNumber", sparePartNumber);
358
359 if (!success)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000360 {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200361 messages::internalError(asyncResp->res);
362 return;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000363 }
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200364
365 if (partNumber != nullptr)
366 {
367 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
368 }
369
370 if (serialNumber != nullptr)
371 {
372 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
373 }
374
375 if (manufacturer != nullptr)
376 {
377 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
378 }
379
380 if (model != nullptr)
381 {
382 asyncResp->res.jsonValue["Model"] = *model;
383 }
384
385 // SparePartNumber is optional on D-Bus
386 // so skip if it is empty
387 if (sparePartNumber != nullptr && !sparePartNumber->empty())
388 {
389 asyncResp->res.jsonValue["SparePartNumber"] =
390 *sparePartNumber;
391 }
392
Nan Zhoucf7eba02022-07-21 23:53:20 +0000393 asyncResp->res.jsonValue["Name"] = chassisId;
394 asyncResp->res.jsonValue["Id"] = chassisId;
395#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
396 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
397 "/redfish/v1/Chassis/" + chassisId + "/Thermal";
398 // Power object
399 asyncResp->res.jsonValue["Power"]["@odata.id"] =
400 "/redfish/v1/Chassis/" + chassisId + "/Power";
401#endif
Xiaochao Ma29739632021-03-02 15:53:13 +0800402#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
403 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
404 crow::utility::urlFromPieces("redfish", "v1", "Chassis",
405 chassisId, "ThermalSubsystem");
Chicago Duan77b36432021-02-05 15:48:26 +0800406 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
407 crow::utility::urlFromPieces("redfish", "v1", "Chassis",
408 chassisId, "PowerSubsystem");
Albert Zhang4ca3ec32021-06-13 14:39:38 +0800409 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
410 crow::utility::urlFromPieces("redfish", "v1", "Chassis",
411 chassisId,
412 "EnvironmentMetrics");
Xiaochao Ma29739632021-03-02 15:53:13 +0800413#endif
Nan Zhoucf7eba02022-07-21 23:53:20 +0000414 // SensorCollection
415 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
416 "/redfish/v1/Chassis/" + chassisId + "/Sensors";
417 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
418
419 nlohmann::json::array_t computerSystems;
420 nlohmann::json::object_t system;
421 system["@odata.id"] = "/redfish/v1/Systems/system";
422 computerSystems.push_back(std::move(system));
423 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
424 std::move(computerSystems);
425
426 nlohmann::json::array_t managedBy;
427 nlohmann::json::object_t manager;
428 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
429 managedBy.push_back(std::move(manager));
430 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
431 std::move(managedBy);
432 getChassisState(asyncResp);
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200433 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000434
435 for (const auto& interface : interfaces2)
436 {
437 if (interface == "xyz.openbmc_project.Common.UUID")
438 {
439 getChassisUUID(asyncResp, connectionName, path);
440 }
441 else if (interface ==
442 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
443 {
444 getChassisLocationCode(asyncResp, connectionName, path);
445 }
446 }
447
448 return;
449 }
450
451 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800452 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000453 },
454 "xyz.openbmc_project.ObjectMapper",
455 "/xyz/openbmc_project/object_mapper",
456 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
457 "/xyz/openbmc_project/inventory", 0, interfaces);
458
459 getPhysicalSecurityData(asyncResp);
460}
461
462inline void
463 handleChassisPatch(App& app, const crow::Request& req,
464 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
465 const std::string& param)
466{
467 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
468 {
469 return;
470 }
471 std::optional<bool> locationIndicatorActive;
472 std::optional<std::string> indicatorLed;
473
474 if (param.empty())
475 {
476 return;
477 }
478
479 if (!json_util::readJsonPatch(
480 req, asyncResp->res, "LocationIndicatorActive",
481 locationIndicatorActive, "IndicatorLED", indicatorLed))
482 {
483 return;
484 }
485
486 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
487 if (!locationIndicatorActive && !indicatorLed)
488 {
489 return; // delete this when we support more patch properties
490 }
491 if (indicatorLed)
492 {
493 asyncResp->res.addHeader(
494 boost::beast::http::field::warning,
495 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
496 }
497
498 const std::array<const char*, 2> interfaces = {
499 "xyz.openbmc_project.Inventory.Item.Board",
500 "xyz.openbmc_project.Inventory.Item.Chassis"};
501
502 const std::string& chassisId = param;
503
504 crow::connections::systemBus->async_method_call(
505 [asyncResp, chassisId, locationIndicatorActive,
506 indicatorLed](const boost::system::error_code ec,
507 const dbus::utility::MapperGetSubTreeResponse& subtree) {
508 if (ec)
509 {
510 messages::internalError(asyncResp->res);
511 return;
512 }
513
514 // Iterate over all retrieved ObjectPaths.
515 for (const std::pair<
516 std::string,
517 std::vector<std::pair<std::string, std::vector<std::string>>>>&
518 object : subtree)
519 {
520 const std::string& path = object.first;
521 const std::vector<std::pair<std::string, std::vector<std::string>>>&
522 connectionNames = object.second;
523
524 sdbusplus::message::object_path objPath(path);
525 if (objPath.filename() != chassisId)
526 {
527 continue;
528 }
529
530 if (connectionNames.empty())
531 {
532 BMCWEB_LOG_ERROR << "Got 0 Connection names";
533 continue;
534 }
535
536 const std::vector<std::string>& interfaces3 =
537 connectionNames[0].second;
538
539 const std::array<const char*, 2> hasIndicatorLed = {
540 "xyz.openbmc_project.Inventory.Item.Panel",
541 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
542 bool indicatorChassis = false;
543 for (const char* interface : hasIndicatorLed)
544 {
545 if (std::find(interfaces3.begin(), interfaces3.end(),
546 interface) != interfaces3.end())
547 {
548 indicatorChassis = true;
549 break;
550 }
551 }
552 if (locationIndicatorActive)
553 {
554 if (indicatorChassis)
555 {
556 setLocationIndicatorActive(asyncResp,
557 *locationIndicatorActive);
558 }
559 else
560 {
561 messages::propertyUnknown(asyncResp->res,
562 "LocationIndicatorActive");
563 }
564 }
565 if (indicatorLed)
566 {
567 if (indicatorChassis)
568 {
569 setIndicatorLedState(asyncResp, *indicatorLed);
570 }
571 else
572 {
573 messages::propertyUnknown(asyncResp->res, "IndicatorLED");
574 }
575 }
576 return;
577 }
578
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800579 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000580 },
581 "xyz.openbmc_project.ObjectMapper",
582 "/xyz/openbmc_project/object_mapper",
583 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
584 "/xyz/openbmc_project/inventory", 0, interfaces);
585}
586
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100587/**
588 * Chassis override class for delivering Chassis Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700589 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100590 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700591inline void requestRoutesChassis(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700592{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700593 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700594 .privileges(redfish::privileges::getChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700595 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000596 std::bind_front(handleChassisGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700597
598 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700599 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700600 .methods(boost::beast::http::verb::patch)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000601 std::bind_front(handleChassisPatch, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700602}
P.K. Leedd99e042020-06-17 19:43:16 +0800603
zhanghch058d1b46d2021-04-01 11:18:24 +0800604inline void
605 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800606{
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700607 const char* busName = "xyz.openbmc_project.ObjectMapper";
608 const char* path = "/xyz/openbmc_project/object_mapper";
609 const char* interface = "xyz.openbmc_project.ObjectMapper";
610 const char* method = "GetSubTreePaths";
P.K. Leedd99e042020-06-17 19:43:16 +0800611
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700612 const std::array<const char*, 1> interfaces = {
613 "xyz.openbmc_project.State.Chassis"};
614
615 // Use mapper to get subtree paths.
P.K. Leedd99e042020-06-17 19:43:16 +0800616 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800617 [asyncResp](
618 const boost::system::error_code ec,
619 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700620 if (ec)
621 {
622 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
623 messages::internalError(asyncResp->res);
624 return;
625 }
626
627 const char* processName = "xyz.openbmc_project.State.Chassis";
628 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
629 const char* destProperty = "RequestedPowerTransition";
630 const std::string propertyValue =
631 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
632 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
633
634 /* Look for system reset chassis path */
635 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
636 chassisList.end())
637 {
638 /* We prefer to reset the full chassis_system, but if it doesn't
639 * exist on some platforms, fall back to a host-only power reset
640 */
641 objectPath = "/xyz/openbmc_project/state/chassis0";
642 }
643
644 crow::connections::systemBus->async_method_call(
Ed Tanous8a592812022-06-04 09:06:59 -0700645 [asyncResp](const boost::system::error_code ec2) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700646 // Use "Set" method to set the property value.
Ed Tanous8a592812022-06-04 09:06:59 -0700647 if (ec2)
P.K. Leedd99e042020-06-17 19:43:16 +0800648 {
Ed Tanous8a592812022-06-04 09:06:59 -0700649 BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec2;
P.K. Leedd99e042020-06-17 19:43:16 +0800650 messages::internalError(asyncResp->res);
651 return;
652 }
653
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 messages::success(asyncResp->res);
655 },
656 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
657 interfaceName, destProperty,
658 dbus::utility::DbusVariantType{propertyValue});
P.K. Leedd99e042020-06-17 19:43:16 +0800659 },
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700660 busName, path, interface, method, "/", 0, interfaces);
P.K. Leedd99e042020-06-17 19:43:16 +0800661}
662
Nan Zhoucf7eba02022-07-21 23:53:20 +0000663inline void handleChassisResetActionInfoPost(
664 App& app, const crow::Request& req,
665 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
666 const std::string& /*chassisId*/)
667{
668 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
669 {
670 return;
671 }
672 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
673
674 std::string resetType;
675
676 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
677 {
678 return;
679 }
680
681 if (resetType != "PowerCycle")
682 {
683 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
684 << resetType;
685 messages::actionParameterNotSupported(asyncResp->res, resetType,
686 "ResetType");
687
688 return;
689 }
690 doChassisPowerCycle(asyncResp);
691}
692
P.K. Leedd99e042020-06-17 19:43:16 +0800693/**
694 * ChassisResetAction class supports the POST method for the Reset
695 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700696 * Function handles POST method request.
697 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800698 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700699
700inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800701{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700702 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700703 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700704 .methods(boost::beast::http::verb::post)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000705 std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
706}
P.K. Leedd99e042020-06-17 19:43:16 +0800707
Nan Zhoucf7eba02022-07-21 23:53:20 +0000708inline void handleChassisResetActionInfoGet(
709 App& app, const crow::Request& req,
710 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
711 const std::string& chassisId)
712{
713 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
714 {
715 return;
716 }
717 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
718 asyncResp->res.jsonValue["@odata.id"] =
719 "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
720 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
P.K. Leedd99e042020-06-17 19:43:16 +0800721
Nan Zhoucf7eba02022-07-21 23:53:20 +0000722 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
723 nlohmann::json::array_t parameters;
724 nlohmann::json::object_t parameter;
725 parameter["Name"] = "ResetType";
726 parameter["Required"] = true;
727 parameter["DataType"] = "String";
728 nlohmann::json::array_t allowed;
729 allowed.push_back("PowerCycle");
730 parameter["AllowableValues"] = std::move(allowed);
731 parameters.push_back(std::move(parameter));
P.K. Leedd99e042020-06-17 19:43:16 +0800732
Nan Zhoucf7eba02022-07-21 23:53:20 +0000733 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700734}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530735
736/**
737 * ChassisResetActionInfo derived class for delivering Chassis
738 * ResetType AllowableValues using ResetInfo schema.
739 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700740inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530741{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700742 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700743 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700744 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000745 std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700746}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530747
Ed Tanous1abe55e2018-09-05 08:30:59 -0700748} // namespace redfish