blob: d5b8d1fc8bcae10131bedd83080c212913730aeb [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
Willy Tu13451e32023-05-24 16:08:18 -070018#include "bmcweb_config.h"
19
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080021#include "dbus_utility.hpp"
James Feistb49ac872019-05-21 15:12:01 -070022#include "health.hpp"
James Feist1c8fba92019-12-20 15:12:07 -080023#include "led.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080024#include "query.hpp"
25#include "registries/privilege_registry.hpp"
26#include "utils/collection.hpp"
27#include "utils/dbus_utils.hpp"
Nan Zhoucf7eba02022-07-21 23:53:20 +000028#include "utils/json_utils.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070029
George Liue99073f2022-12-09 11:06:16 +080030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070032#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020033#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034
George Liu7a1dbc42022-12-07 16:03:22 +080035#include <array>
36#include <string_view>
37
Ed Tanous1abe55e2018-09-05 08:30:59 -070038namespace redfish
39{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010040
41/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060042 * @brief Retrieves chassis state properties over dbus
43 *
44 * @param[in] aResp - Shared pointer for completing asynchronous calls.
45 *
46 * @return None.
47 */
zhanghch058d1b46d2021-04-01 11:18:24 +080048inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060049{
Jonathan Doman1e1e5982021-06-11 09:36:17 -070050 // crow::connections::systemBus->async_method_call(
51 sdbusplus::asio::getProperty<std::string>(
52 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
53 "/xyz/openbmc_project/state/chassis0",
54 "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080055 [aResp{std::move(aResp)}](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070056 const std::string& chassisState) {
Ed Tanous002d39b2022-05-31 08:59:27 -070057 if (ec)
58 {
59 if (ec == boost::system::errc::host_unreachable)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060060 {
Ed Tanous002d39b2022-05-31 08:59:27 -070061 // Service not available, no error, just don't return
62 // chassis state info
63 BMCWEB_LOG_DEBUG << "Service not available " << ec;
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060064 return;
65 }
Andrew Geissler51dab2a2023-05-30 15:07:46 -040066 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -070067 messages::internalError(aResp->res);
68 return;
69 }
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060070
Ed Tanous002d39b2022-05-31 08:59:27 -070071 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
72 // Verify Chassis State
73 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
74 {
75 aResp->res.jsonValue["PowerState"] = "On";
76 aResp->res.jsonValue["Status"]["State"] = "Enabled";
77 }
78 else if (chassisState ==
79 "xyz.openbmc_project.State.Chassis.PowerState.Off")
80 {
81 aResp->res.jsonValue["PowerState"] = "Off";
82 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
83 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070084 });
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060085}
86
zhanghch058d1b46d2021-04-01 11:18:24 +080087inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Ed Tanous23a21a12020-07-25 04:45:05 +000088 const std::string& service,
89 const std::string& objPath)
Qiang XUc1819422019-02-27 13:51:32 +080090{
91 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
92
Jonathan Doman1e1e5982021-06-11 09:36:17 -070093 sdbusplus::asio::getProperty<std::string>(
94 *crow::connections::systemBus, service, objPath,
95 "xyz.openbmc_project.Chassis.Intrusion", "Status",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -080096 [aResp{std::move(aResp)}](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070097 const std::string& value) {
Ed Tanous002d39b2022-05-31 08:59:27 -070098 if (ec)
99 {
100 // do not add err msg in redfish response, because this is not
101 // mandatory property
102 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
103 return;
104 }
Qiang XUc1819422019-02-27 13:51:32 +0800105
Ed Tanous002d39b2022-05-31 08:59:27 -0700106 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
107 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700108 });
Qiang XUc1819422019-02-27 13:51:32 +0800109}
110
111/**
112 * Retrieves physical security properties over dbus
113 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800114inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp)
Qiang XUc1819422019-02-27 13:51:32 +0800115{
George Liue99073f2022-12-09 11:06:16 +0800116 constexpr std::array<std::string_view, 1> interfaces = {
117 "xyz.openbmc_project.Chassis.Intrusion"};
118 dbus::utility::getSubTree(
119 "/xyz/openbmc_project/Intrusion", 1, interfaces,
Qiang XUc1819422019-02-27 13:51:32 +0800120 [aResp{std::move(aResp)}](
George Liue99073f2022-12-09 11:06:16 +0800121 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800122 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700123 if (ec)
124 {
125 // do not add err msg in redfish response, because this is not
126 // mandatory property
127 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
128 return;
129 }
130 // Iterate over all retrieved ObjectPaths.
131 for (const auto& object : subtree)
132 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500133 if (!object.second.empty())
Qiang XUc1819422019-02-27 13:51:32 +0800134 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500135 const auto service = object.second.front();
Ed Tanous002d39b2022-05-31 08:59:27 -0700136 getIntrusionByService(aResp, service.first, object.first);
Qiang XUc1819422019-02-27 13:51:32 +0800137 return;
138 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700139 }
George Liue99073f2022-12-09 11:06:16 +0800140 });
Qiang XUc1819422019-02-27 13:51:32 +0800141}
142
Nan Zhoucf7eba02022-07-21 23:53:20 +0000143inline void handleChassisCollectionGet(
144 App& app, const crow::Request& req,
145 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
146{
147 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
148 {
149 return;
150 }
151 asyncResp->res.jsonValue["@odata.type"] =
152 "#ChassisCollection.ChassisCollection";
153 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
154 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
155
George Liu7a1dbc42022-12-07 16:03:22 +0800156 constexpr std::array<std::string_view, 2> interfaces{
157 "xyz.openbmc_project.Inventory.Item.Board",
158 "xyz.openbmc_project.Inventory.Item.Chassis"};
Nan Zhoucf7eba02022-07-21 23:53:20 +0000159 collection_util::getCollectionMembers(
George Liu7a1dbc42022-12-07 16:03:22 +0800160 asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000161}
162
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100163/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100164 * ChassisCollection derived class for delivering Chassis Collection Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700165 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100166 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700167inline void requestRoutesChassisCollection(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700168{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700169 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
Ed Tanoused398212021-06-09 17:05:54 -0700170 .privileges(redfish::privileges::getChassisCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700171 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000172 std::bind_front(handleChassisCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700173}
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100174
Willy Tu308f70c2021-09-28 20:24:52 -0700175inline void
176 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
177 const std::string& connectionName,
178 const std::string& path)
179{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700180 sdbusplus::asio::getProperty<std::string>(
181 *crow::connections::systemBus, connectionName, path,
182 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800183 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700184 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700185 if (ec)
186 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400187 BMCWEB_LOG_ERROR << "DBUS response error for Location";
Ed Tanous002d39b2022-05-31 08:59:27 -0700188 messages::internalError(asyncResp->res);
189 return;
190 }
Willy Tu308f70c2021-09-28 20:24:52 -0700191
Ed Tanous002d39b2022-05-31 08:59:27 -0700192 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
193 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700194 });
Willy Tu308f70c2021-09-28 20:24:52 -0700195}
196
197inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
198 const std::string& connectionName,
199 const std::string& path)
200{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700201 sdbusplus::asio::getProperty<std::string>(
202 *crow::connections::systemBus, connectionName, path,
203 "xyz.openbmc_project.Common.UUID", "UUID",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800204 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700205 const std::string& chassisUUID) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700206 if (ec)
207 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400208 BMCWEB_LOG_ERROR << "DBUS response error for UUID";
Ed Tanous002d39b2022-05-31 08:59:27 -0700209 messages::internalError(asyncResp->res);
210 return;
211 }
212 asyncResp->res.jsonValue["UUID"] = chassisUUID;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700213 });
Willy Tu308f70c2021-09-28 20:24:52 -0700214}
215
Nan Zhoucf7eba02022-07-21 23:53:20 +0000216inline void
217 handleChassisGet(App& app, const crow::Request& req,
218 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
219 const std::string& chassisId)
220{
221 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
222 {
223 return;
224 }
George Liue99073f2022-12-09 11:06:16 +0800225 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000226 "xyz.openbmc_project.Inventory.Item.Board",
227 "xyz.openbmc_project.Inventory.Item.Chassis"};
228
George Liue99073f2022-12-09 11:06:16 +0800229 dbus::utility::getSubTree(
230 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000231 [asyncResp, chassisId(std::string(chassisId))](
George Liue99073f2022-12-09 11:06:16 +0800232 const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000233 const dbus::utility::MapperGetSubTreeResponse& subtree) {
234 if (ec)
235 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400236 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000237 messages::internalError(asyncResp->res);
238 return;
239 }
240 // Iterate over all retrieved ObjectPaths.
241 for (const std::pair<
242 std::string,
243 std::vector<std::pair<std::string, std::vector<std::string>>>>&
244 object : subtree)
245 {
246 const std::string& path = object.first;
247 const std::vector<std::pair<std::string, std::vector<std::string>>>&
248 connectionNames = object.second;
249
250 sdbusplus::message::object_path objPath(path);
251 if (objPath.filename() != chassisId)
252 {
253 continue;
254 }
255
256 auto health = std::make_shared<HealthPopulate>(asyncResp);
257
Willy Tu13451e32023-05-24 16:08:18 -0700258 if constexpr (bmcwebEnableHealthPopulate)
259 {
260 dbus::utility::getAssociationEndPoints(
261 path + "/all_sensors",
262 [health](const boost::system::error_code& ec2,
263 const dbus::utility::MapperEndPoints& resp) {
264 if (ec2)
265 {
266 return; // no sensors = no failures
267 }
268 health->inventory = resp;
269 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000270
Willy Tu13451e32023-05-24 16:08:18 -0700271 health->populate();
272 }
Nan Zhoucf7eba02022-07-21 23:53:20 +0000273
274 if (connectionNames.empty())
275 {
276 BMCWEB_LOG_ERROR << "Got 0 Connection names";
277 continue;
278 }
279
280 asyncResp->res.jsonValue["@odata.type"] =
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530281 "#Chassis.v1_22_0.Chassis";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000282 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700283 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000284 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
285 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
286 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700287 boost::urls::format(
288 "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000289 asyncResp->res
290 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700291 boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
292 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000293 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700294 "/redfish/v1/Systems/system/PCIeDevices";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000295
George Liu6c3e9452023-03-03 13:55:29 +0800296 dbus::utility::getAssociationEndPoints(
297 path + "/drive",
298 [asyncResp,
299 chassisId](const boost::system::error_code& ec3,
300 const dbus::utility::MapperEndPoints& resp) {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000301 if (ec3 || resp.empty())
302 {
303 return; // no drives = no failures
304 }
305
306 nlohmann::json reference;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700307 reference["@odata.id"] = boost::urls::format(
308 "/redfish/v1/Chassis/{}/Drives", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000309 asyncResp->res.jsonValue["Drives"] = std::move(reference);
310 });
311
312 const std::string& connectionName = connectionNames[0].first;
313
314 const std::vector<std::string>& interfaces2 =
315 connectionNames[0].second;
316 const std::array<const char*, 2> hasIndicatorLed = {
317 "xyz.openbmc_project.Inventory.Item.Panel",
318 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
319
320 const std::string assetTagInterface =
321 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530322 const std::string replaceableInterface =
323 "xyz.openbmc_project.Inventory.Decorator.Replaceable";
324 for (const auto& interface : interfaces2)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000325 {
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530326 if (interface == assetTagInterface)
327 {
328 sdbusplus::asio::getProperty<std::string>(
329 *crow::connections::systemBus, connectionName, path,
330 assetTagInterface, "AssetTag",
331 [asyncResp,
332 chassisId](const boost::system::error_code& ec2,
333 const std::string& property) {
334 if (ec2)
335 {
336 BMCWEB_LOG_ERROR
337 << "DBus response error for AssetTag: " << ec2;
338 messages::internalError(asyncResp->res);
339 return;
340 }
341 asyncResp->res.jsonValue["AssetTag"] = property;
342 });
343 }
344 else if (interface == replaceableInterface)
345 {
346 sdbusplus::asio::getProperty<bool>(
347 *crow::connections::systemBus, connectionName, path,
348 replaceableInterface, "HotPluggable",
349 [asyncResp,
350 chassisId](const boost::system::error_code& ec2,
351 const bool property) {
352 if (ec2)
353 {
354 BMCWEB_LOG_ERROR
355 << "DBus response error for HotPluggable: "
356 << ec2;
357 messages::internalError(asyncResp->res);
358 return;
359 }
360 asyncResp->res.jsonValue["HotPluggable"] = property;
361 });
362 }
Nan Zhoucf7eba02022-07-21 23:53:20 +0000363 }
364
365 for (const char* interface : hasIndicatorLed)
366 {
367 if (std::find(interfaces2.begin(), interfaces2.end(),
368 interface) != interfaces2.end())
369 {
370 getIndicatorLedState(asyncResp);
371 getLocationIndicatorActive(asyncResp);
372 break;
373 }
374 }
375
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200376 sdbusplus::asio::getAllProperties(
377 *crow::connections::systemBus, connectionName, path,
378 "xyz.openbmc_project.Inventory.Decorator.Asset",
Nan Zhoucf7eba02022-07-21 23:53:20 +0000379 [asyncResp, chassisId(std::string(chassisId))](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800380 const boost::system::error_code& /*ec2*/,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000381 const dbus::utility::DBusPropertiesMap& propertiesList) {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200382 const std::string* partNumber = nullptr;
383 const std::string* serialNumber = nullptr;
384 const std::string* manufacturer = nullptr;
385 const std::string* model = nullptr;
386 const std::string* sparePartNumber = nullptr;
387
388 const bool success = sdbusplus::unpackPropertiesNoThrow(
389 dbus_utils::UnpackErrorPrinter(), propertiesList,
390 "PartNumber", partNumber, "SerialNumber", serialNumber,
391 "Manufacturer", manufacturer, "Model", model,
392 "SparePartNumber", sparePartNumber);
393
394 if (!success)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000395 {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200396 messages::internalError(asyncResp->res);
397 return;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000398 }
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200399
400 if (partNumber != nullptr)
401 {
402 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
403 }
404
405 if (serialNumber != nullptr)
406 {
407 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
408 }
409
410 if (manufacturer != nullptr)
411 {
412 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
413 }
414
415 if (model != nullptr)
416 {
417 asyncResp->res.jsonValue["Model"] = *model;
418 }
419
420 // SparePartNumber is optional on D-Bus
421 // so skip if it is empty
422 if (sparePartNumber != nullptr && !sparePartNumber->empty())
423 {
424 asyncResp->res.jsonValue["SparePartNumber"] =
425 *sparePartNumber;
426 }
427
Nan Zhoucf7eba02022-07-21 23:53:20 +0000428 asyncResp->res.jsonValue["Name"] = chassisId;
429 asyncResp->res.jsonValue["Id"] = chassisId;
430#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
431 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700432 boost::urls::format("/redfish/v1/Chassis/{}/Thermal",
433 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000434 // Power object
435 asyncResp->res.jsonValue["Power"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700436 boost::urls::format("/redfish/v1/Chassis/{}/Power",
437 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000438#endif
Xiaochao Ma29739632021-03-02 15:53:13 +0800439#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
440 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700441 boost::urls::format(
442 "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId);
Chicago Duan77b36432021-02-05 15:48:26 +0800443 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700444 boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
445 chassisId);
Albert Zhang4ca3ec32021-06-13 14:39:38 +0800446 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700447 boost::urls::format(
448 "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId);
Xiaochao Ma29739632021-03-02 15:53:13 +0800449#endif
Nan Zhoucf7eba02022-07-21 23:53:20 +0000450 // SensorCollection
451 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700452 boost::urls::format("/redfish/v1/Chassis/{}/Sensors",
453 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000454 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
455
456 nlohmann::json::array_t computerSystems;
457 nlohmann::json::object_t system;
458 system["@odata.id"] = "/redfish/v1/Systems/system";
Patrick Williamsad539542023-05-12 10:10:08 -0500459 computerSystems.emplace_back(std::move(system));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000460 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
461 std::move(computerSystems);
462
463 nlohmann::json::array_t managedBy;
464 nlohmann::json::object_t manager;
465 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
Patrick Williamsad539542023-05-12 10:10:08 -0500466 managedBy.emplace_back(std::move(manager));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000467 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
468 std::move(managedBy);
469 getChassisState(asyncResp);
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200470 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000471
472 for (const auto& interface : interfaces2)
473 {
474 if (interface == "xyz.openbmc_project.Common.UUID")
475 {
476 getChassisUUID(asyncResp, connectionName, path);
477 }
478 else if (interface ==
479 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
480 {
481 getChassisLocationCode(asyncResp, connectionName, path);
482 }
483 }
484
485 return;
486 }
487
488 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800489 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800490 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000491
492 getPhysicalSecurityData(asyncResp);
493}
494
495inline void
496 handleChassisPatch(App& app, const crow::Request& req,
497 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
498 const std::string& param)
499{
500 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
501 {
502 return;
503 }
504 std::optional<bool> locationIndicatorActive;
505 std::optional<std::string> indicatorLed;
506
507 if (param.empty())
508 {
509 return;
510 }
511
512 if (!json_util::readJsonPatch(
513 req, asyncResp->res, "LocationIndicatorActive",
514 locationIndicatorActive, "IndicatorLED", indicatorLed))
515 {
516 return;
517 }
518
519 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
520 if (!locationIndicatorActive && !indicatorLed)
521 {
522 return; // delete this when we support more patch properties
523 }
524 if (indicatorLed)
525 {
526 asyncResp->res.addHeader(
527 boost::beast::http::field::warning,
528 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
529 }
530
George Liue99073f2022-12-09 11:06:16 +0800531 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000532 "xyz.openbmc_project.Inventory.Item.Board",
533 "xyz.openbmc_project.Inventory.Item.Chassis"};
534
535 const std::string& chassisId = param;
536
George Liue99073f2022-12-09 11:06:16 +0800537 dbus::utility::getSubTree(
538 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000539 [asyncResp, chassisId, locationIndicatorActive,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800540 indicatorLed](const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000541 const dbus::utility::MapperGetSubTreeResponse& subtree) {
542 if (ec)
543 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400544 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000545 messages::internalError(asyncResp->res);
546 return;
547 }
548
549 // Iterate over all retrieved ObjectPaths.
550 for (const std::pair<
551 std::string,
552 std::vector<std::pair<std::string, std::vector<std::string>>>>&
553 object : subtree)
554 {
555 const std::string& path = object.first;
556 const std::vector<std::pair<std::string, std::vector<std::string>>>&
557 connectionNames = object.second;
558
559 sdbusplus::message::object_path objPath(path);
560 if (objPath.filename() != chassisId)
561 {
562 continue;
563 }
564
565 if (connectionNames.empty())
566 {
567 BMCWEB_LOG_ERROR << "Got 0 Connection names";
568 continue;
569 }
570
571 const std::vector<std::string>& interfaces3 =
572 connectionNames[0].second;
573
574 const std::array<const char*, 2> hasIndicatorLed = {
575 "xyz.openbmc_project.Inventory.Item.Panel",
576 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
577 bool indicatorChassis = false;
578 for (const char* interface : hasIndicatorLed)
579 {
580 if (std::find(interfaces3.begin(), interfaces3.end(),
581 interface) != interfaces3.end())
582 {
583 indicatorChassis = true;
584 break;
585 }
586 }
587 if (locationIndicatorActive)
588 {
589 if (indicatorChassis)
590 {
591 setLocationIndicatorActive(asyncResp,
592 *locationIndicatorActive);
593 }
594 else
595 {
596 messages::propertyUnknown(asyncResp->res,
597 "LocationIndicatorActive");
598 }
599 }
600 if (indicatorLed)
601 {
602 if (indicatorChassis)
603 {
604 setIndicatorLedState(asyncResp, *indicatorLed);
605 }
606 else
607 {
608 messages::propertyUnknown(asyncResp->res, "IndicatorLED");
609 }
610 }
611 return;
612 }
613
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800614 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800615 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000616}
617
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100618/**
619 * Chassis override class for delivering Chassis Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700620 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100621 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700622inline void requestRoutesChassis(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700623{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700624 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700625 .privileges(redfish::privileges::getChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700626 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000627 std::bind_front(handleChassisGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700628
629 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700630 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700631 .methods(boost::beast::http::verb::patch)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000632 std::bind_front(handleChassisPatch, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700633}
P.K. Leedd99e042020-06-17 19:43:16 +0800634
zhanghch058d1b46d2021-04-01 11:18:24 +0800635inline void
636 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800637{
George Liu7a1dbc42022-12-07 16:03:22 +0800638 constexpr std::array<std::string_view, 1> interfaces = {
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700639 "xyz.openbmc_project.State.Chassis"};
640
641 // Use mapper to get subtree paths.
George Liu7a1dbc42022-12-07 16:03:22 +0800642 dbus::utility::getSubTreePaths(
643 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800644 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +0800645 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800646 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700647 if (ec)
648 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400649 BMCWEB_LOG_ERROR << "[mapper] Bad D-Bus request error: " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -0700650 messages::internalError(asyncResp->res);
651 return;
652 }
653
654 const char* processName = "xyz.openbmc_project.State.Chassis";
655 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
656 const char* destProperty = "RequestedPowerTransition";
657 const std::string propertyValue =
658 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
659 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
660
661 /* Look for system reset chassis path */
662 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
663 chassisList.end())
664 {
665 /* We prefer to reset the full chassis_system, but if it doesn't
666 * exist on some platforms, fall back to a host-only power reset
667 */
668 objectPath = "/xyz/openbmc_project/state/chassis0";
669 }
670
671 crow::connections::systemBus->async_method_call(
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800672 [asyncResp](const boost::system::error_code& ec2) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700673 // Use "Set" method to set the property value.
Ed Tanous8a592812022-06-04 09:06:59 -0700674 if (ec2)
P.K. Leedd99e042020-06-17 19:43:16 +0800675 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400676 BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec2;
P.K. Leedd99e042020-06-17 19:43:16 +0800677 messages::internalError(asyncResp->res);
678 return;
679 }
680
Ed Tanous002d39b2022-05-31 08:59:27 -0700681 messages::success(asyncResp->res);
682 },
683 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
684 interfaceName, destProperty,
685 dbus::utility::DbusVariantType{propertyValue});
George Liu7a1dbc42022-12-07 16:03:22 +0800686 });
P.K. Leedd99e042020-06-17 19:43:16 +0800687}
688
Nan Zhoucf7eba02022-07-21 23:53:20 +0000689inline void handleChassisResetActionInfoPost(
690 App& app, const crow::Request& req,
691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
692 const std::string& /*chassisId*/)
693{
694 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
695 {
696 return;
697 }
698 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
699
700 std::string resetType;
701
702 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
703 {
704 return;
705 }
706
707 if (resetType != "PowerCycle")
708 {
709 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
710 << resetType;
711 messages::actionParameterNotSupported(asyncResp->res, resetType,
712 "ResetType");
713
714 return;
715 }
716 doChassisPowerCycle(asyncResp);
717}
718
P.K. Leedd99e042020-06-17 19:43:16 +0800719/**
720 * ChassisResetAction class supports the POST method for the Reset
721 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700722 * Function handles POST method request.
723 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800724 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700725
726inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800727{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700728 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700729 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700730 .methods(boost::beast::http::verb::post)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000731 std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
732}
P.K. Leedd99e042020-06-17 19:43:16 +0800733
Nan Zhoucf7eba02022-07-21 23:53:20 +0000734inline void handleChassisResetActionInfoGet(
735 App& app, const crow::Request& req,
736 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
737 const std::string& chassisId)
738{
739 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
740 {
741 return;
742 }
743 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700744 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
745 "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000746 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
P.K. Leedd99e042020-06-17 19:43:16 +0800747
Nan Zhoucf7eba02022-07-21 23:53:20 +0000748 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
749 nlohmann::json::array_t parameters;
750 nlohmann::json::object_t parameter;
751 parameter["Name"] = "ResetType";
752 parameter["Required"] = true;
753 parameter["DataType"] = "String";
754 nlohmann::json::array_t allowed;
Patrick Williamsad539542023-05-12 10:10:08 -0500755 allowed.emplace_back("PowerCycle");
Nan Zhoucf7eba02022-07-21 23:53:20 +0000756 parameter["AllowableValues"] = std::move(allowed);
Patrick Williamsad539542023-05-12 10:10:08 -0500757 parameters.emplace_back(std::move(parameter));
P.K. Leedd99e042020-06-17 19:43:16 +0800758
Nan Zhoucf7eba02022-07-21 23:53:20 +0000759 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700760}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530761
762/**
763 * ChassisResetActionInfo derived class for delivering Chassis
764 * ResetType AllowableValues using ResetInfo schema.
765 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700766inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530767{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700768 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700769 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700770 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000771 std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700772}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530773
Ed Tanous1abe55e2018-09-05 08:30:59 -0700774} // namespace redfish