blob: a2744210cf8ed36ee5d992eccdb01d43756e9c44 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
James Feistb49ac872019-05-21 15:12:01 -070020#include "health.hpp"
James Feist1c8fba92019-12-20 15:12:07 -080021#include "led.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080022#include "query.hpp"
23#include "registries/privilege_registry.hpp"
24#include "utils/collection.hpp"
25#include "utils/dbus_utils.hpp"
Nan Zhoucf7eba02022-07-21 23:53:20 +000026#include "utils/json_utils.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070027
George Liue99073f2022-12-09 11:06:16 +080028#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070029#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070030#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020031#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050032
George Liu7a1dbc42022-12-07 16:03:22 +080033#include <array>
34#include <string_view>
35
Ed Tanous1abe55e2018-09-05 08:30:59 -070036namespace redfish
37{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010038
39/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060040 * @brief Retrieves chassis state properties over dbus
41 *
42 * @param[in] aResp - Shared pointer for completing asynchronous calls.
43 *
44 * @return None.
45 */
zhanghch058d1b46d2021-04-01 11:18:24 +080046inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060047{
Jonathan Doman1e1e5982021-06-11 09:36:17 -070048 // crow::connections::systemBus->async_method_call(
49 sdbusplus::asio::getProperty<std::string>(
50 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
51 "/xyz/openbmc_project/state/chassis0",
52 "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080053 [aResp{std::move(aResp)}](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070054 const std::string& chassisState) {
Ed Tanous002d39b2022-05-31 08:59:27 -070055 if (ec)
56 {
57 if (ec == boost::system::errc::host_unreachable)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060058 {
Ed Tanous002d39b2022-05-31 08:59:27 -070059 // Service not available, no error, just don't return
60 // chassis state info
61 BMCWEB_LOG_DEBUG << "Service not available " << ec;
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060062 return;
63 }
Ed Tanous002d39b2022-05-31 08:59:27 -070064 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
65 messages::internalError(aResp->res);
66 return;
67 }
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060068
Ed Tanous002d39b2022-05-31 08:59:27 -070069 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
70 // Verify Chassis State
71 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
72 {
73 aResp->res.jsonValue["PowerState"] = "On";
74 aResp->res.jsonValue["Status"]["State"] = "Enabled";
75 }
76 else if (chassisState ==
77 "xyz.openbmc_project.State.Chassis.PowerState.Off")
78 {
79 aResp->res.jsonValue["PowerState"] = "Off";
80 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
81 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070082 });
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060083}
84
zhanghch058d1b46d2021-04-01 11:18:24 +080085inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Ed Tanous23a21a12020-07-25 04:45:05 +000086 const std::string& service,
87 const std::string& objPath)
Qiang XUc1819422019-02-27 13:51:32 +080088{
89 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
90
Jonathan Doman1e1e5982021-06-11 09:36:17 -070091 sdbusplus::asio::getProperty<std::string>(
92 *crow::connections::systemBus, service, objPath,
93 "xyz.openbmc_project.Chassis.Intrusion", "Status",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080094 [aResp{std::move(aResp)}](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070095 const std::string& value) {
Ed Tanous002d39b2022-05-31 08:59:27 -070096 if (ec)
97 {
98 // do not add err msg in redfish response, because this is not
99 // mandatory property
100 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
101 return;
102 }
Qiang XUc1819422019-02-27 13:51:32 +0800103
Ed Tanous002d39b2022-05-31 08:59:27 -0700104 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
105 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700106 });
Qiang XUc1819422019-02-27 13:51:32 +0800107}
108
109/**
110 * Retrieves physical security properties over dbus
111 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800112inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp)
Qiang XUc1819422019-02-27 13:51:32 +0800113{
George Liue99073f2022-12-09 11:06:16 +0800114 constexpr std::array<std::string_view, 1> interfaces = {
115 "xyz.openbmc_project.Chassis.Intrusion"};
116 dbus::utility::getSubTree(
117 "/xyz/openbmc_project/Intrusion", 1, interfaces,
Qiang XUc1819422019-02-27 13:51:32 +0800118 [aResp{std::move(aResp)}](
George Liue99073f2022-12-09 11:06:16 +0800119 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800120 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700121 if (ec)
122 {
123 // do not add err msg in redfish response, because this is not
124 // mandatory property
125 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
126 return;
127 }
128 // Iterate over all retrieved ObjectPaths.
129 for (const auto& object : subtree)
130 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500131 if (!object.second.empty())
Qiang XUc1819422019-02-27 13:51:32 +0800132 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500133 const auto service = object.second.front();
Ed Tanous002d39b2022-05-31 08:59:27 -0700134 getIntrusionByService(aResp, service.first, object.first);
Qiang XUc1819422019-02-27 13:51:32 +0800135 return;
136 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700137 }
George Liue99073f2022-12-09 11:06:16 +0800138 });
Qiang XUc1819422019-02-27 13:51:32 +0800139}
140
Nan Zhoucf7eba02022-07-21 23:53:20 +0000141inline void handleChassisCollectionGet(
142 App& app, const crow::Request& req,
143 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
144{
145 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
146 {
147 return;
148 }
149 asyncResp->res.jsonValue["@odata.type"] =
150 "#ChassisCollection.ChassisCollection";
151 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
152 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
153
George Liu7a1dbc42022-12-07 16:03:22 +0800154 constexpr std::array<std::string_view, 2> interfaces{
155 "xyz.openbmc_project.Inventory.Item.Board",
156 "xyz.openbmc_project.Inventory.Item.Chassis"};
Nan Zhoucf7eba02022-07-21 23:53:20 +0000157 collection_util::getCollectionMembers(
George Liu7a1dbc42022-12-07 16:03:22 +0800158 asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000159}
160
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100161/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100162 * ChassisCollection derived class for delivering Chassis Collection Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700163 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100164 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165inline void requestRoutesChassisCollection(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700166{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
Ed Tanoused398212021-06-09 17:05:54 -0700168 .privileges(redfish::privileges::getChassisCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000170 std::bind_front(handleChassisCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171}
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100172
Willy Tu308f70c2021-09-28 20:24:52 -0700173inline void
174 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
175 const std::string& connectionName,
176 const std::string& path)
177{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700178 sdbusplus::asio::getProperty<std::string>(
179 *crow::connections::systemBus, connectionName, path,
180 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800181 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700182 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700183 if (ec)
184 {
185 BMCWEB_LOG_DEBUG << "DBUS response error for Location";
186 messages::internalError(asyncResp->res);
187 return;
188 }
Willy Tu308f70c2021-09-28 20:24:52 -0700189
Ed Tanous002d39b2022-05-31 08:59:27 -0700190 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
191 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700192 });
Willy Tu308f70c2021-09-28 20:24:52 -0700193}
194
195inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
196 const std::string& connectionName,
197 const std::string& path)
198{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700199 sdbusplus::asio::getProperty<std::string>(
200 *crow::connections::systemBus, connectionName, path,
201 "xyz.openbmc_project.Common.UUID", "UUID",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800202 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700203 const std::string& chassisUUID) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700204 if (ec)
205 {
206 BMCWEB_LOG_DEBUG << "DBUS response error for UUID";
207 messages::internalError(asyncResp->res);
208 return;
209 }
210 asyncResp->res.jsonValue["UUID"] = chassisUUID;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700211 });
Willy Tu308f70c2021-09-28 20:24:52 -0700212}
213
Nan Zhoucf7eba02022-07-21 23:53:20 +0000214inline void
215 handleChassisGet(App& app, const crow::Request& req,
216 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
217 const std::string& chassisId)
218{
219 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
220 {
221 return;
222 }
George Liue99073f2022-12-09 11:06:16 +0800223 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000224 "xyz.openbmc_project.Inventory.Item.Board",
225 "xyz.openbmc_project.Inventory.Item.Chassis"};
226
George Liue99073f2022-12-09 11:06:16 +0800227 dbus::utility::getSubTree(
228 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000229 [asyncResp, chassisId(std::string(chassisId))](
George Liue99073f2022-12-09 11:06:16 +0800230 const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000231 const dbus::utility::MapperGetSubTreeResponse& subtree) {
232 if (ec)
233 {
234 messages::internalError(asyncResp->res);
235 return;
236 }
237 // Iterate over all retrieved ObjectPaths.
238 for (const std::pair<
239 std::string,
240 std::vector<std::pair<std::string, std::vector<std::string>>>>&
241 object : subtree)
242 {
243 const std::string& path = object.first;
244 const std::vector<std::pair<std::string, std::vector<std::string>>>&
245 connectionNames = object.second;
246
247 sdbusplus::message::object_path objPath(path);
248 if (objPath.filename() != chassisId)
249 {
250 continue;
251 }
252
253 auto health = std::make_shared<HealthPopulate>(asyncResp);
254
George Liu6c3e9452023-03-03 13:55:29 +0800255 dbus::utility::getAssociationEndPoints(
256 path + "/all_sensors",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800257 [health](const boost::system::error_code& ec2,
George Liu6c3e9452023-03-03 13:55:29 +0800258 const dbus::utility::MapperEndPoints& resp) {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000259 if (ec2)
260 {
261 return; // no sensors = no failures
262 }
263 health->inventory = resp;
264 });
265
266 health->populate();
267
268 if (connectionNames.empty())
269 {
270 BMCWEB_LOG_ERROR << "Got 0 Connection names";
271 continue;
272 }
273
274 asyncResp->res.jsonValue["@odata.type"] =
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530275 "#Chassis.v1_22_0.Chassis";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000276 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700277 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000278 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
279 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
280 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700281 boost::urls::format(
282 "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000283 asyncResp->res
284 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700285 boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
286 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000287 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700288 "/redfish/v1/Systems/system/PCIeDevices";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000289
George Liu6c3e9452023-03-03 13:55:29 +0800290 dbus::utility::getAssociationEndPoints(
291 path + "/drive",
292 [asyncResp,
293 chassisId](const boost::system::error_code& ec3,
294 const dbus::utility::MapperEndPoints& resp) {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000295 if (ec3 || resp.empty())
296 {
297 return; // no drives = no failures
298 }
299
300 nlohmann::json reference;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700301 reference["@odata.id"] = boost::urls::format(
302 "/redfish/v1/Chassis/{}/Drives", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000303 asyncResp->res.jsonValue["Drives"] = std::move(reference);
304 });
305
306 const std::string& connectionName = connectionNames[0].first;
307
308 const std::vector<std::string>& interfaces2 =
309 connectionNames[0].second;
310 const std::array<const char*, 2> hasIndicatorLed = {
311 "xyz.openbmc_project.Inventory.Item.Panel",
312 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
313
314 const std::string assetTagInterface =
315 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530316 const std::string replaceableInterface =
317 "xyz.openbmc_project.Inventory.Decorator.Replaceable";
318 for (const auto& interface : interfaces2)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000319 {
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530320 if (interface == assetTagInterface)
321 {
322 sdbusplus::asio::getProperty<std::string>(
323 *crow::connections::systemBus, connectionName, path,
324 assetTagInterface, "AssetTag",
325 [asyncResp,
326 chassisId](const boost::system::error_code& ec2,
327 const std::string& property) {
328 if (ec2)
329 {
330 BMCWEB_LOG_ERROR
331 << "DBus response error for AssetTag: " << ec2;
332 messages::internalError(asyncResp->res);
333 return;
334 }
335 asyncResp->res.jsonValue["AssetTag"] = property;
336 });
337 }
338 else if (interface == replaceableInterface)
339 {
340 sdbusplus::asio::getProperty<bool>(
341 *crow::connections::systemBus, connectionName, path,
342 replaceableInterface, "HotPluggable",
343 [asyncResp,
344 chassisId](const boost::system::error_code& ec2,
345 const bool property) {
346 if (ec2)
347 {
348 BMCWEB_LOG_ERROR
349 << "DBus response error for HotPluggable: "
350 << ec2;
351 messages::internalError(asyncResp->res);
352 return;
353 }
354 asyncResp->res.jsonValue["HotPluggable"] = property;
355 });
356 }
Nan Zhoucf7eba02022-07-21 23:53:20 +0000357 }
358
359 for (const char* interface : hasIndicatorLed)
360 {
361 if (std::find(interfaces2.begin(), interfaces2.end(),
362 interface) != interfaces2.end())
363 {
364 getIndicatorLedState(asyncResp);
365 getLocationIndicatorActive(asyncResp);
366 break;
367 }
368 }
369
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200370 sdbusplus::asio::getAllProperties(
371 *crow::connections::systemBus, connectionName, path,
372 "xyz.openbmc_project.Inventory.Decorator.Asset",
Nan Zhoucf7eba02022-07-21 23:53:20 +0000373 [asyncResp, chassisId(std::string(chassisId))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800374 const boost::system::error_code& /*ec2*/,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000375 const dbus::utility::DBusPropertiesMap& propertiesList) {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200376 const std::string* partNumber = nullptr;
377 const std::string* serialNumber = nullptr;
378 const std::string* manufacturer = nullptr;
379 const std::string* model = nullptr;
380 const std::string* sparePartNumber = nullptr;
381
382 const bool success = sdbusplus::unpackPropertiesNoThrow(
383 dbus_utils::UnpackErrorPrinter(), propertiesList,
384 "PartNumber", partNumber, "SerialNumber", serialNumber,
385 "Manufacturer", manufacturer, "Model", model,
386 "SparePartNumber", sparePartNumber);
387
388 if (!success)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000389 {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200390 messages::internalError(asyncResp->res);
391 return;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000392 }
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200393
394 if (partNumber != nullptr)
395 {
396 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
397 }
398
399 if (serialNumber != nullptr)
400 {
401 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
402 }
403
404 if (manufacturer != nullptr)
405 {
406 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
407 }
408
409 if (model != nullptr)
410 {
411 asyncResp->res.jsonValue["Model"] = *model;
412 }
413
414 // SparePartNumber is optional on D-Bus
415 // so skip if it is empty
416 if (sparePartNumber != nullptr && !sparePartNumber->empty())
417 {
418 asyncResp->res.jsonValue["SparePartNumber"] =
419 *sparePartNumber;
420 }
421
Nan Zhoucf7eba02022-07-21 23:53:20 +0000422 asyncResp->res.jsonValue["Name"] = chassisId;
423 asyncResp->res.jsonValue["Id"] = chassisId;
424#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
425 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700426 boost::urls::format("/redfish/v1/Chassis/{}/Thermal",
427 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000428 // Power object
429 asyncResp->res.jsonValue["Power"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700430 boost::urls::format("/redfish/v1/Chassis/{}/Power",
431 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000432#endif
Xiaochao Ma29739632021-03-02 15:53:13 +0800433#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
434 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700435 boost::urls::format(
436 "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId);
Chicago Duan77b36432021-02-05 15:48:26 +0800437 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700438 boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
439 chassisId);
Albert Zhang4ca3ec32021-06-13 14:39:38 +0800440 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700441 boost::urls::format(
442 "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId);
Xiaochao Ma29739632021-03-02 15:53:13 +0800443#endif
Nan Zhoucf7eba02022-07-21 23:53:20 +0000444 // SensorCollection
445 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700446 boost::urls::format("/redfish/v1/Chassis/{}/Sensors",
447 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000448 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
449
450 nlohmann::json::array_t computerSystems;
451 nlohmann::json::object_t system;
452 system["@odata.id"] = "/redfish/v1/Systems/system";
Patrick Williamsad539542023-05-12 10:10:08 -0500453 computerSystems.emplace_back(std::move(system));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000454 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
455 std::move(computerSystems);
456
457 nlohmann::json::array_t managedBy;
458 nlohmann::json::object_t manager;
459 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
Patrick Williamsad539542023-05-12 10:10:08 -0500460 managedBy.emplace_back(std::move(manager));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000461 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
462 std::move(managedBy);
463 getChassisState(asyncResp);
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200464 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000465
466 for (const auto& interface : interfaces2)
467 {
468 if (interface == "xyz.openbmc_project.Common.UUID")
469 {
470 getChassisUUID(asyncResp, connectionName, path);
471 }
472 else if (interface ==
473 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
474 {
475 getChassisLocationCode(asyncResp, connectionName, path);
476 }
477 }
478
479 return;
480 }
481
482 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800483 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800484 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000485
486 getPhysicalSecurityData(asyncResp);
487}
488
489inline void
490 handleChassisPatch(App& app, const crow::Request& req,
491 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
492 const std::string& param)
493{
494 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
495 {
496 return;
497 }
498 std::optional<bool> locationIndicatorActive;
499 std::optional<std::string> indicatorLed;
500
501 if (param.empty())
502 {
503 return;
504 }
505
506 if (!json_util::readJsonPatch(
507 req, asyncResp->res, "LocationIndicatorActive",
508 locationIndicatorActive, "IndicatorLED", indicatorLed))
509 {
510 return;
511 }
512
513 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
514 if (!locationIndicatorActive && !indicatorLed)
515 {
516 return; // delete this when we support more patch properties
517 }
518 if (indicatorLed)
519 {
520 asyncResp->res.addHeader(
521 boost::beast::http::field::warning,
522 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
523 }
524
George Liue99073f2022-12-09 11:06:16 +0800525 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000526 "xyz.openbmc_project.Inventory.Item.Board",
527 "xyz.openbmc_project.Inventory.Item.Chassis"};
528
529 const std::string& chassisId = param;
530
George Liue99073f2022-12-09 11:06:16 +0800531 dbus::utility::getSubTree(
532 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000533 [asyncResp, chassisId, locationIndicatorActive,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800534 indicatorLed](const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000535 const dbus::utility::MapperGetSubTreeResponse& subtree) {
536 if (ec)
537 {
538 messages::internalError(asyncResp->res);
539 return;
540 }
541
542 // Iterate over all retrieved ObjectPaths.
543 for (const std::pair<
544 std::string,
545 std::vector<std::pair<std::string, std::vector<std::string>>>>&
546 object : subtree)
547 {
548 const std::string& path = object.first;
549 const std::vector<std::pair<std::string, std::vector<std::string>>>&
550 connectionNames = object.second;
551
552 sdbusplus::message::object_path objPath(path);
553 if (objPath.filename() != chassisId)
554 {
555 continue;
556 }
557
558 if (connectionNames.empty())
559 {
560 BMCWEB_LOG_ERROR << "Got 0 Connection names";
561 continue;
562 }
563
564 const std::vector<std::string>& interfaces3 =
565 connectionNames[0].second;
566
567 const std::array<const char*, 2> hasIndicatorLed = {
568 "xyz.openbmc_project.Inventory.Item.Panel",
569 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
570 bool indicatorChassis = false;
571 for (const char* interface : hasIndicatorLed)
572 {
573 if (std::find(interfaces3.begin(), interfaces3.end(),
574 interface) != interfaces3.end())
575 {
576 indicatorChassis = true;
577 break;
578 }
579 }
580 if (locationIndicatorActive)
581 {
582 if (indicatorChassis)
583 {
584 setLocationIndicatorActive(asyncResp,
585 *locationIndicatorActive);
586 }
587 else
588 {
589 messages::propertyUnknown(asyncResp->res,
590 "LocationIndicatorActive");
591 }
592 }
593 if (indicatorLed)
594 {
595 if (indicatorChassis)
596 {
597 setIndicatorLedState(asyncResp, *indicatorLed);
598 }
599 else
600 {
601 messages::propertyUnknown(asyncResp->res, "IndicatorLED");
602 }
603 }
604 return;
605 }
606
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800607 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800608 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000609}
610
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100611/**
612 * Chassis override class for delivering Chassis Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700613 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100614 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700615inline void requestRoutesChassis(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700616{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700617 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700618 .privileges(redfish::privileges::getChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700619 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000620 std::bind_front(handleChassisGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621
622 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700623 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700624 .methods(boost::beast::http::verb::patch)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000625 std::bind_front(handleChassisPatch, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700626}
P.K. Leedd99e042020-06-17 19:43:16 +0800627
zhanghch058d1b46d2021-04-01 11:18:24 +0800628inline void
629 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800630{
George Liu7a1dbc42022-12-07 16:03:22 +0800631 constexpr std::array<std::string_view, 1> interfaces = {
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700632 "xyz.openbmc_project.State.Chassis"};
633
634 // Use mapper to get subtree paths.
George Liu7a1dbc42022-12-07 16:03:22 +0800635 dbus::utility::getSubTreePaths(
636 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800637 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +0800638 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800639 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700640 if (ec)
641 {
642 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
643 messages::internalError(asyncResp->res);
644 return;
645 }
646
647 const char* processName = "xyz.openbmc_project.State.Chassis";
648 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
649 const char* destProperty = "RequestedPowerTransition";
650 const std::string propertyValue =
651 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
652 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
653
654 /* Look for system reset chassis path */
655 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
656 chassisList.end())
657 {
658 /* We prefer to reset the full chassis_system, but if it doesn't
659 * exist on some platforms, fall back to a host-only power reset
660 */
661 objectPath = "/xyz/openbmc_project/state/chassis0";
662 }
663
664 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800665 [asyncResp](const boost::system::error_code& ec2) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700666 // Use "Set" method to set the property value.
Ed Tanous8a592812022-06-04 09:06:59 -0700667 if (ec2)
P.K. Leedd99e042020-06-17 19:43:16 +0800668 {
Ed Tanous8a592812022-06-04 09:06:59 -0700669 BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec2;
P.K. Leedd99e042020-06-17 19:43:16 +0800670 messages::internalError(asyncResp->res);
671 return;
672 }
673
Ed Tanous002d39b2022-05-31 08:59:27 -0700674 messages::success(asyncResp->res);
675 },
676 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
677 interfaceName, destProperty,
678 dbus::utility::DbusVariantType{propertyValue});
George Liu7a1dbc42022-12-07 16:03:22 +0800679 });
P.K. Leedd99e042020-06-17 19:43:16 +0800680}
681
Nan Zhoucf7eba02022-07-21 23:53:20 +0000682inline void handleChassisResetActionInfoPost(
683 App& app, const crow::Request& req,
684 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
685 const std::string& /*chassisId*/)
686{
687 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
688 {
689 return;
690 }
691 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
692
693 std::string resetType;
694
695 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
696 {
697 return;
698 }
699
700 if (resetType != "PowerCycle")
701 {
702 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
703 << resetType;
704 messages::actionParameterNotSupported(asyncResp->res, resetType,
705 "ResetType");
706
707 return;
708 }
709 doChassisPowerCycle(asyncResp);
710}
711
P.K. Leedd99e042020-06-17 19:43:16 +0800712/**
713 * ChassisResetAction class supports the POST method for the Reset
714 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700715 * Function handles POST method request.
716 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800717 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700718
719inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800720{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700721 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700722 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700723 .methods(boost::beast::http::verb::post)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000724 std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
725}
P.K. Leedd99e042020-06-17 19:43:16 +0800726
Nan Zhoucf7eba02022-07-21 23:53:20 +0000727inline void handleChassisResetActionInfoGet(
728 App& app, const crow::Request& req,
729 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
730 const std::string& chassisId)
731{
732 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
733 {
734 return;
735 }
736 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700737 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
738 "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000739 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
P.K. Leedd99e042020-06-17 19:43:16 +0800740
Nan Zhoucf7eba02022-07-21 23:53:20 +0000741 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
742 nlohmann::json::array_t parameters;
743 nlohmann::json::object_t parameter;
744 parameter["Name"] = "ResetType";
745 parameter["Required"] = true;
746 parameter["DataType"] = "String";
747 nlohmann::json::array_t allowed;
Patrick Williamsad539542023-05-12 10:10:08 -0500748 allowed.emplace_back("PowerCycle");
Nan Zhoucf7eba02022-07-21 23:53:20 +0000749 parameter["AllowableValues"] = std::move(allowed);
Patrick Williamsad539542023-05-12 10:10:08 -0500750 parameters.emplace_back(std::move(parameter));
P.K. Leedd99e042020-06-17 19:43:16 +0800751
Nan Zhoucf7eba02022-07-21 23:53:20 +0000752 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700753}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530754
755/**
756 * ChassisResetActionInfo derived class for delivering Chassis
757 * ResetType AllowableValues using ResetInfo schema.
758 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700759inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530760{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700761 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700762 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700763 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000764 std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700765}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530766
Ed Tanous1abe55e2018-09-05 08:30:59 -0700767} // namespace redfish