blob: 8ac7caa77c27f576439ddbe364e01f1bcceca51b [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>
Andrew Geisslerfc903b32023-05-31 14:15:42 -040033#include <sdbusplus/message.hpp>
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +020034#include <sdbusplus/unpack_properties.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035
George Liu7a1dbc42022-12-07 16:03:22 +080036#include <array>
37#include <string_view>
38
Ed Tanous1abe55e2018-09-05 08:30:59 -070039namespace redfish
40{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010041
42/**
Willy Tu5e577bc2022-07-26 00:41:55 +000043 * @brief Retrieves resources over dbus to link to the chassis
44 *
45 * @param[in] asyncResp - Shared pointer for completing asynchronous
46 * calls
47 * @param[in] path - Chassis dbus path to look for the storage.
48 *
49 * Calls the Association endpoints on the path + "/storage" and add the link of
50 * json["Links"]["Storage@odata.count"] =
51 * {"@odata.id", "/redfish/v1/Storage/" + resourceId}
52 *
53 * @return None.
54 */
55inline void getStorageLink(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
56 const sdbusplus::message::object_path& path)
57{
58 sdbusplus::asio::getProperty<std::vector<std::string>>(
59 *crow::connections::systemBus, "xyz.openbmc_project.ObjectMapper",
60 (path / "storage").str, "xyz.openbmc_project.Association", "endpoints",
61 [asyncResp](const boost::system::error_code ec,
62 const std::vector<std::string>& storageList) {
63 if (ec)
64 {
65 BMCWEB_LOG_DEBUG << "getStorageLink got DBUS response error";
66 return;
67 }
68
69 nlohmann::json::array_t storages;
70 for (const std::string& storagePath : storageList)
71 {
72 std::string id =
73 sdbusplus::message::object_path(storagePath).filename();
74 if (id.empty())
75 {
76 continue;
77 }
78
79 nlohmann::json::object_t storage;
80 storage["@odata.id"] = boost::urls::format(
81 "/redfish/v1/Systems/system/Storage/{}", id);
82 storages.emplace_back(std::move(storage));
83 }
84 asyncResp->res.jsonValue["Links"]["Storage@odata.count"] =
85 storages.size();
86 asyncResp->res.jsonValue["Links"]["Storage"] = std::move(storages);
87 });
88}
89
90/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060091 * @brief Retrieves chassis state properties over dbus
92 *
Ed Tanousac106bf2023-06-07 09:24:59 -070093 * @param[in] asyncResp - Shared pointer for completing asynchronous calls.
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060094 *
95 * @return None.
96 */
Ed Tanousac106bf2023-06-07 09:24:59 -070097inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060098{
Jonathan Doman1e1e5982021-06-11 09:36:17 -070099 // crow::connections::systemBus->async_method_call(
100 sdbusplus::asio::getProperty<std::string>(
101 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
102 "/xyz/openbmc_project/state/chassis0",
103 "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
Ed Tanousac106bf2023-06-07 09:24:59 -0700104 [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
105 const std::string& chassisState) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700106 if (ec)
107 {
108 if (ec == boost::system::errc::host_unreachable)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600109 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700110 // Service not available, no error, just don't return
111 // chassis state info
112 BMCWEB_LOG_DEBUG << "Service not available " << ec;
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600113 return;
114 }
Ed Tanousac106bf2023-06-07 09:24:59 -0700115 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
116 messages::internalError(asyncResp->res);
Ed Tanous002d39b2022-05-31 08:59:27 -0700117 return;
118 }
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600119
Ed Tanous002d39b2022-05-31 08:59:27 -0700120 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
121 // Verify Chassis State
122 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
123 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700124 asyncResp->res.jsonValue["PowerState"] = "On";
125 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Ed Tanous002d39b2022-05-31 08:59:27 -0700126 }
127 else if (chassisState ==
128 "xyz.openbmc_project.State.Chassis.PowerState.Off")
129 {
Ed Tanousac106bf2023-06-07 09:24:59 -0700130 asyncResp->res.jsonValue["PowerState"] = "Off";
131 asyncResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
Ed Tanous002d39b2022-05-31 08:59:27 -0700132 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700133 });
Gunnar Millsbeeca0a2019-02-14 16:30:45 -0600134}
135
Ed Tanousac106bf2023-06-07 09:24:59 -0700136inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> asyncResp,
Ed Tanous23a21a12020-07-25 04:45:05 +0000137 const std::string& service,
138 const std::string& objPath)
Qiang XUc1819422019-02-27 13:51:32 +0800139{
140 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
141
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700142 sdbusplus::asio::getProperty<std::string>(
143 *crow::connections::systemBus, service, objPath,
144 "xyz.openbmc_project.Chassis.Intrusion", "Status",
Ed Tanousac106bf2023-06-07 09:24:59 -0700145 [asyncResp{std::move(asyncResp)}](const boost::system::error_code& ec,
146 const std::string& value) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700147 if (ec)
148 {
149 // do not add err msg in redfish response, because this is not
150 // mandatory property
151 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
152 return;
153 }
Qiang XUc1819422019-02-27 13:51:32 +0800154
Ed Tanousac106bf2023-06-07 09:24:59 -0700155 asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] =
156 1;
157 asyncResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700158 });
Qiang XUc1819422019-02-27 13:51:32 +0800159}
160
161/**
162 * Retrieves physical security properties over dbus
163 */
Ed Tanousac106bf2023-06-07 09:24:59 -0700164inline void
165 getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> asyncResp)
Qiang XUc1819422019-02-27 13:51:32 +0800166{
George Liue99073f2022-12-09 11:06:16 +0800167 constexpr std::array<std::string_view, 1> interfaces = {
168 "xyz.openbmc_project.Chassis.Intrusion"};
169 dbus::utility::getSubTree(
170 "/xyz/openbmc_project/Intrusion", 1, interfaces,
Ed Tanousac106bf2023-06-07 09:24:59 -0700171 [asyncResp{std::move(asyncResp)}](
George Liue99073f2022-12-09 11:06:16 +0800172 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800173 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700174 if (ec)
175 {
176 // do not add err msg in redfish response, because this is not
177 // mandatory property
178 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
179 return;
180 }
181 // Iterate over all retrieved ObjectPaths.
182 for (const auto& object : subtree)
183 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500184 if (!object.second.empty())
Qiang XUc1819422019-02-27 13:51:32 +0800185 {
Patrick Williams840a9ff2023-05-12 10:18:43 -0500186 const auto service = object.second.front();
Ed Tanousac106bf2023-06-07 09:24:59 -0700187 getIntrusionByService(asyncResp, service.first, object.first);
Qiang XUc1819422019-02-27 13:51:32 +0800188 return;
189 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700190 }
George Liue99073f2022-12-09 11:06:16 +0800191 });
Qiang XUc1819422019-02-27 13:51:32 +0800192}
193
Nan Zhoucf7eba02022-07-21 23:53:20 +0000194inline void handleChassisCollectionGet(
195 App& app, const crow::Request& req,
196 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
197{
198 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
199 {
200 return;
201 }
202 asyncResp->res.jsonValue["@odata.type"] =
203 "#ChassisCollection.ChassisCollection";
204 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
205 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
206
George Liu7a1dbc42022-12-07 16:03:22 +0800207 constexpr std::array<std::string_view, 2> interfaces{
208 "xyz.openbmc_project.Inventory.Item.Board",
209 "xyz.openbmc_project.Inventory.Item.Chassis"};
Nan Zhoucf7eba02022-07-21 23:53:20 +0000210 collection_util::getCollectionMembers(
George Liu7a1dbc42022-12-07 16:03:22 +0800211 asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000212}
213
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100214/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100215 * ChassisCollection derived class for delivering Chassis Collection Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700216 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100217 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700218inline void requestRoutesChassisCollection(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700219{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700220 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
Ed Tanoused398212021-06-09 17:05:54 -0700221 .privileges(redfish::privileges::getChassisCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700222 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000223 std::bind_front(handleChassisCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700224}
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100225
Willy Tu308f70c2021-09-28 20:24:52 -0700226inline void
227 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
228 const std::string& connectionName,
229 const std::string& path)
230{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700231 sdbusplus::asio::getProperty<std::string>(
232 *crow::connections::systemBus, connectionName, path,
233 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800234 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700235 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700236 if (ec)
237 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400238 BMCWEB_LOG_ERROR << "DBUS response error for Location";
Ed Tanous002d39b2022-05-31 08:59:27 -0700239 messages::internalError(asyncResp->res);
240 return;
241 }
Willy Tu308f70c2021-09-28 20:24:52 -0700242
Ed Tanous002d39b2022-05-31 08:59:27 -0700243 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
244 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700245 });
Willy Tu308f70c2021-09-28 20:24:52 -0700246}
247
248inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
249 const std::string& connectionName,
250 const std::string& path)
251{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700252 sdbusplus::asio::getProperty<std::string>(
253 *crow::connections::systemBus, connectionName, path,
254 "xyz.openbmc_project.Common.UUID", "UUID",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800255 [asyncResp](const boost::system::error_code& ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700256 const std::string& chassisUUID) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700257 if (ec)
258 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400259 BMCWEB_LOG_ERROR << "DBUS response error for UUID";
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 messages::internalError(asyncResp->res);
261 return;
262 }
263 asyncResp->res.jsonValue["UUID"] = chassisUUID;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700264 });
Willy Tu308f70c2021-09-28 20:24:52 -0700265}
266
Nan Zhoucf7eba02022-07-21 23:53:20 +0000267inline void
268 handleChassisGet(App& app, const crow::Request& req,
269 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
270 const std::string& chassisId)
271{
272 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
273 {
274 return;
275 }
George Liue99073f2022-12-09 11:06:16 +0800276 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000277 "xyz.openbmc_project.Inventory.Item.Board",
278 "xyz.openbmc_project.Inventory.Item.Chassis"};
279
George Liue99073f2022-12-09 11:06:16 +0800280 dbus::utility::getSubTree(
281 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000282 [asyncResp, chassisId(std::string(chassisId))](
George Liue99073f2022-12-09 11:06:16 +0800283 const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000284 const dbus::utility::MapperGetSubTreeResponse& subtree) {
285 if (ec)
286 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400287 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000288 messages::internalError(asyncResp->res);
289 return;
290 }
291 // Iterate over all retrieved ObjectPaths.
292 for (const std::pair<
293 std::string,
294 std::vector<std::pair<std::string, std::vector<std::string>>>>&
295 object : subtree)
296 {
297 const std::string& path = object.first;
298 const std::vector<std::pair<std::string, std::vector<std::string>>>&
299 connectionNames = object.second;
300
301 sdbusplus::message::object_path objPath(path);
302 if (objPath.filename() != chassisId)
303 {
304 continue;
305 }
306
307 auto health = std::make_shared<HealthPopulate>(asyncResp);
308
Willy Tu13451e32023-05-24 16:08:18 -0700309 if constexpr (bmcwebEnableHealthPopulate)
310 {
311 dbus::utility::getAssociationEndPoints(
312 path + "/all_sensors",
313 [health](const boost::system::error_code& ec2,
314 const dbus::utility::MapperEndPoints& resp) {
315 if (ec2)
316 {
317 return; // no sensors = no failures
318 }
319 health->inventory = resp;
320 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000321
Willy Tu13451e32023-05-24 16:08:18 -0700322 health->populate();
323 }
Nan Zhoucf7eba02022-07-21 23:53:20 +0000324
325 if (connectionNames.empty())
326 {
327 BMCWEB_LOG_ERROR << "Got 0 Connection names";
328 continue;
329 }
330
331 asyncResp->res.jsonValue["@odata.type"] =
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530332 "#Chassis.v1_22_0.Chassis";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000333 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700334 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000335 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
336 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
337 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700338 boost::urls::format(
339 "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000340 asyncResp->res
341 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700342 boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo",
343 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000344 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700345 "/redfish/v1/Systems/system/PCIeDevices";
Nan Zhoucf7eba02022-07-21 23:53:20 +0000346
George Liu6c3e9452023-03-03 13:55:29 +0800347 dbus::utility::getAssociationEndPoints(
348 path + "/drive",
349 [asyncResp,
350 chassisId](const boost::system::error_code& ec3,
351 const dbus::utility::MapperEndPoints& resp) {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000352 if (ec3 || resp.empty())
353 {
354 return; // no drives = no failures
355 }
356
357 nlohmann::json reference;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700358 reference["@odata.id"] = boost::urls::format(
359 "/redfish/v1/Chassis/{}/Drives", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000360 asyncResp->res.jsonValue["Drives"] = std::move(reference);
361 });
362
363 const std::string& connectionName = connectionNames[0].first;
364
365 const std::vector<std::string>& interfaces2 =
366 connectionNames[0].second;
367 const std::array<const char*, 2> hasIndicatorLed = {
368 "xyz.openbmc_project.Inventory.Item.Panel",
369 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
370
371 const std::string assetTagInterface =
372 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530373 const std::string replaceableInterface =
374 "xyz.openbmc_project.Inventory.Decorator.Replaceable";
375 for (const auto& interface : interfaces2)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000376 {
Logananth Sundararaj523d4862023-01-24 11:56:28 +0530377 if (interface == assetTagInterface)
378 {
379 sdbusplus::asio::getProperty<std::string>(
380 *crow::connections::systemBus, connectionName, path,
381 assetTagInterface, "AssetTag",
382 [asyncResp,
383 chassisId](const boost::system::error_code& ec2,
384 const std::string& property) {
385 if (ec2)
386 {
387 BMCWEB_LOG_ERROR
388 << "DBus response error for AssetTag: " << ec2;
389 messages::internalError(asyncResp->res);
390 return;
391 }
392 asyncResp->res.jsonValue["AssetTag"] = property;
393 });
394 }
395 else if (interface == replaceableInterface)
396 {
397 sdbusplus::asio::getProperty<bool>(
398 *crow::connections::systemBus, connectionName, path,
399 replaceableInterface, "HotPluggable",
400 [asyncResp,
401 chassisId](const boost::system::error_code& ec2,
402 const bool property) {
403 if (ec2)
404 {
405 BMCWEB_LOG_ERROR
406 << "DBus response error for HotPluggable: "
407 << ec2;
408 messages::internalError(asyncResp->res);
409 return;
410 }
411 asyncResp->res.jsonValue["HotPluggable"] = property;
412 });
413 }
Nan Zhoucf7eba02022-07-21 23:53:20 +0000414 }
415
416 for (const char* interface : hasIndicatorLed)
417 {
418 if (std::find(interfaces2.begin(), interfaces2.end(),
419 interface) != interfaces2.end())
420 {
421 getIndicatorLedState(asyncResp);
422 getLocationIndicatorActive(asyncResp);
423 break;
424 }
425 }
426
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200427 sdbusplus::asio::getAllProperties(
428 *crow::connections::systemBus, connectionName, path,
429 "xyz.openbmc_project.Inventory.Decorator.Asset",
Willy Tu5e577bc2022-07-26 00:41:55 +0000430 [asyncResp, chassisId(std::string(chassisId)),
431 path](const boost::system::error_code& /*ec2*/,
432 const dbus::utility::DBusPropertiesMap& propertiesList) {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200433 const std::string* partNumber = nullptr;
434 const std::string* serialNumber = nullptr;
435 const std::string* manufacturer = nullptr;
436 const std::string* model = nullptr;
437 const std::string* sparePartNumber = nullptr;
438
439 const bool success = sdbusplus::unpackPropertiesNoThrow(
440 dbus_utils::UnpackErrorPrinter(), propertiesList,
441 "PartNumber", partNumber, "SerialNumber", serialNumber,
442 "Manufacturer", manufacturer, "Model", model,
443 "SparePartNumber", sparePartNumber);
444
445 if (!success)
Nan Zhoucf7eba02022-07-21 23:53:20 +0000446 {
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200447 messages::internalError(asyncResp->res);
448 return;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000449 }
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200450
451 if (partNumber != nullptr)
452 {
453 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
454 }
455
456 if (serialNumber != nullptr)
457 {
458 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
459 }
460
461 if (manufacturer != nullptr)
462 {
463 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
464 }
465
466 if (model != nullptr)
467 {
468 asyncResp->res.jsonValue["Model"] = *model;
469 }
470
471 // SparePartNumber is optional on D-Bus
472 // so skip if it is empty
473 if (sparePartNumber != nullptr && !sparePartNumber->empty())
474 {
475 asyncResp->res.jsonValue["SparePartNumber"] =
476 *sparePartNumber;
477 }
478
Nan Zhoucf7eba02022-07-21 23:53:20 +0000479 asyncResp->res.jsonValue["Name"] = chassisId;
480 asyncResp->res.jsonValue["Id"] = chassisId;
481#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
482 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700483 boost::urls::format("/redfish/v1/Chassis/{}/Thermal",
484 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000485 // Power object
486 asyncResp->res.jsonValue["Power"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700487 boost::urls::format("/redfish/v1/Chassis/{}/Power",
488 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000489#endif
Xiaochao Ma29739632021-03-02 15:53:13 +0800490#ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM
491 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700492 boost::urls::format(
493 "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId);
Chicago Duan77b36432021-02-05 15:48:26 +0800494 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700495 boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem",
496 chassisId);
Albert Zhang4ca3ec32021-06-13 14:39:38 +0800497 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700498 boost::urls::format(
499 "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId);
Xiaochao Ma29739632021-03-02 15:53:13 +0800500#endif
Nan Zhoucf7eba02022-07-21 23:53:20 +0000501 // SensorCollection
502 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700503 boost::urls::format("/redfish/v1/Chassis/{}/Sensors",
504 chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000505 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
506
507 nlohmann::json::array_t computerSystems;
508 nlohmann::json::object_t system;
509 system["@odata.id"] = "/redfish/v1/Systems/system";
Patrick Williamsad539542023-05-12 10:10:08 -0500510 computerSystems.emplace_back(std::move(system));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000511 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
512 std::move(computerSystems);
513
514 nlohmann::json::array_t managedBy;
515 nlohmann::json::object_t manager;
516 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
Patrick Williamsad539542023-05-12 10:10:08 -0500517 managedBy.emplace_back(std::move(manager));
Nan Zhoucf7eba02022-07-21 23:53:20 +0000518 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
519 std::move(managedBy);
520 getChassisState(asyncResp);
Willy Tu5e577bc2022-07-26 00:41:55 +0000521 getStorageLink(asyncResp, path);
Krzysztof Grobelny86d89ed2022-08-29 14:49:20 +0200522 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000523
524 for (const auto& interface : interfaces2)
525 {
526 if (interface == "xyz.openbmc_project.Common.UUID")
527 {
528 getChassisUUID(asyncResp, connectionName, path);
529 }
530 else if (interface ==
531 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
532 {
533 getChassisLocationCode(asyncResp, connectionName, path);
534 }
535 }
536
537 return;
538 }
539
540 // Couldn't find an object with that name. return an error
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800541 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800542 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000543
544 getPhysicalSecurityData(asyncResp);
545}
546
547inline void
548 handleChassisPatch(App& app, const crow::Request& req,
549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
550 const std::string& param)
551{
552 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
553 {
554 return;
555 }
556 std::optional<bool> locationIndicatorActive;
557 std::optional<std::string> indicatorLed;
558
559 if (param.empty())
560 {
561 return;
562 }
563
564 if (!json_util::readJsonPatch(
565 req, asyncResp->res, "LocationIndicatorActive",
566 locationIndicatorActive, "IndicatorLED", indicatorLed))
567 {
568 return;
569 }
570
571 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
572 if (!locationIndicatorActive && !indicatorLed)
573 {
574 return; // delete this when we support more patch properties
575 }
576 if (indicatorLed)
577 {
578 asyncResp->res.addHeader(
579 boost::beast::http::field::warning,
580 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
581 }
582
George Liue99073f2022-12-09 11:06:16 +0800583 constexpr std::array<std::string_view, 2> interfaces = {
Nan Zhoucf7eba02022-07-21 23:53:20 +0000584 "xyz.openbmc_project.Inventory.Item.Board",
585 "xyz.openbmc_project.Inventory.Item.Chassis"};
586
587 const std::string& chassisId = param;
588
George Liue99073f2022-12-09 11:06:16 +0800589 dbus::utility::getSubTree(
590 "/xyz/openbmc_project/inventory", 0, interfaces,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000591 [asyncResp, chassisId, locationIndicatorActive,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800592 indicatorLed](const boost::system::error_code& ec,
Nan Zhoucf7eba02022-07-21 23:53:20 +0000593 const dbus::utility::MapperGetSubTreeResponse& subtree) {
594 if (ec)
595 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400596 BMCWEB_LOG_ERROR << "DBUS response error " << ec;
Nan Zhoucf7eba02022-07-21 23:53:20 +0000597 messages::internalError(asyncResp->res);
598 return;
599 }
600
601 // Iterate over all retrieved ObjectPaths.
602 for (const std::pair<
603 std::string,
604 std::vector<std::pair<std::string, std::vector<std::string>>>>&
605 object : subtree)
606 {
607 const std::string& path = object.first;
608 const std::vector<std::pair<std::string, std::vector<std::string>>>&
609 connectionNames = object.second;
610
611 sdbusplus::message::object_path objPath(path);
612 if (objPath.filename() != chassisId)
613 {
614 continue;
615 }
616
617 if (connectionNames.empty())
618 {
619 BMCWEB_LOG_ERROR << "Got 0 Connection names";
620 continue;
621 }
622
623 const std::vector<std::string>& interfaces3 =
624 connectionNames[0].second;
625
626 const std::array<const char*, 2> hasIndicatorLed = {
627 "xyz.openbmc_project.Inventory.Item.Panel",
628 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
629 bool indicatorChassis = false;
630 for (const char* interface : hasIndicatorLed)
631 {
632 if (std::find(interfaces3.begin(), interfaces3.end(),
633 interface) != interfaces3.end())
634 {
635 indicatorChassis = true;
636 break;
637 }
638 }
639 if (locationIndicatorActive)
640 {
641 if (indicatorChassis)
642 {
643 setLocationIndicatorActive(asyncResp,
644 *locationIndicatorActive);
645 }
646 else
647 {
648 messages::propertyUnknown(asyncResp->res,
649 "LocationIndicatorActive");
650 }
651 }
652 if (indicatorLed)
653 {
654 if (indicatorChassis)
655 {
656 setIndicatorLedState(asyncResp, *indicatorLed);
657 }
658 else
659 {
660 messages::propertyUnknown(asyncResp->res, "IndicatorLED");
661 }
662 }
663 return;
664 }
665
Jiaqing Zhaod8a5d5d2022-08-05 16:21:51 +0800666 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
George Liue99073f2022-12-09 11:06:16 +0800667 });
Nan Zhoucf7eba02022-07-21 23:53:20 +0000668}
669
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100670/**
671 * Chassis override class for delivering Chassis Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700672 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100673 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700674inline void requestRoutesChassis(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700675{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700676 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700677 .privileges(redfish::privileges::getChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700678 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000679 std::bind_front(handleChassisGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700680
681 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700682 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700683 .methods(boost::beast::http::verb::patch)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000684 std::bind_front(handleChassisPatch, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700685}
P.K. Leedd99e042020-06-17 19:43:16 +0800686
Andrew Geisslerfc903b32023-05-31 14:15:42 -0400687/**
688 * Handle error responses from d-bus for chassis power cycles
689 */
690inline void handleChassisPowerCycleError(const boost::system::error_code& ec,
691 const sdbusplus::message_t& eMsg,
692 crow::Response& res)
693{
694 if (eMsg.get_error() == nullptr)
695 {
696 BMCWEB_LOG_ERROR << "D-Bus response error: " << ec;
697 messages::internalError(res);
698 return;
699 }
700 std::string_view errorMessage = eMsg.get_error()->name;
701
702 // If operation failed due to BMC not being in Ready state, tell
703 // user to retry in a bit
704 if (errorMessage ==
705 std::string_view("xyz.openbmc_project.State.Chassis.Error.BMCNotReady"))
706 {
707 BMCWEB_LOG_DEBUG << "BMC not ready, operation not allowed right now";
708 messages::serviceTemporarilyUnavailable(res, "10");
709 return;
710 }
711
712 BMCWEB_LOG_ERROR << "Chassis Power Cycle fail " << ec
713 << " sdbusplus:" << errorMessage;
714 messages::internalError(res);
715}
716
zhanghch058d1b46d2021-04-01 11:18:24 +0800717inline void
718 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800719{
George Liu7a1dbc42022-12-07 16:03:22 +0800720 constexpr std::array<std::string_view, 1> interfaces = {
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700721 "xyz.openbmc_project.State.Chassis"};
722
723 // Use mapper to get subtree paths.
George Liu7a1dbc42022-12-07 16:03:22 +0800724 dbus::utility::getSubTreePaths(
725 "/", 0, interfaces,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800726 [asyncResp](
George Liu7a1dbc42022-12-07 16:03:22 +0800727 const boost::system::error_code& ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800728 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700729 if (ec)
730 {
Andrew Geissler51dab2a2023-05-30 15:07:46 -0400731 BMCWEB_LOG_ERROR << "[mapper] Bad D-Bus request error: " << ec;
Ed Tanous002d39b2022-05-31 08:59:27 -0700732 messages::internalError(asyncResp->res);
733 return;
734 }
735
736 const char* processName = "xyz.openbmc_project.State.Chassis";
737 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
738 const char* destProperty = "RequestedPowerTransition";
739 const std::string propertyValue =
740 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
741 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
742
743 /* Look for system reset chassis path */
744 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
745 chassisList.end())
746 {
747 /* We prefer to reset the full chassis_system, but if it doesn't
748 * exist on some platforms, fall back to a host-only power reset
749 */
750 objectPath = "/xyz/openbmc_project/state/chassis0";
751 }
752
753 crow::connections::systemBus->async_method_call(
Andrew Geisslerfc903b32023-05-31 14:15:42 -0400754 [asyncResp](const boost::system::error_code& ec2,
755 sdbusplus::message_t& sdbusErrMsg) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700756 // Use "Set" method to set the property value.
Ed Tanous8a592812022-06-04 09:06:59 -0700757 if (ec2)
P.K. Leedd99e042020-06-17 19:43:16 +0800758 {
Andrew Geisslerfc903b32023-05-31 14:15:42 -0400759 handleChassisPowerCycleError(ec2, sdbusErrMsg, asyncResp->res);
760
P.K. Leedd99e042020-06-17 19:43:16 +0800761 return;
762 }
763
Ed Tanous002d39b2022-05-31 08:59:27 -0700764 messages::success(asyncResp->res);
765 },
766 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
767 interfaceName, destProperty,
768 dbus::utility::DbusVariantType{propertyValue});
George Liu7a1dbc42022-12-07 16:03:22 +0800769 });
P.K. Leedd99e042020-06-17 19:43:16 +0800770}
771
Nan Zhoucf7eba02022-07-21 23:53:20 +0000772inline void handleChassisResetActionInfoPost(
773 App& app, const crow::Request& req,
774 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
775 const std::string& /*chassisId*/)
776{
777 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
778 {
779 return;
780 }
781 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
782
783 std::string resetType;
784
785 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
786 {
787 return;
788 }
789
790 if (resetType != "PowerCycle")
791 {
792 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
793 << resetType;
794 messages::actionParameterNotSupported(asyncResp->res, resetType,
795 "ResetType");
796
797 return;
798 }
799 doChassisPowerCycle(asyncResp);
800}
801
P.K. Leedd99e042020-06-17 19:43:16 +0800802/**
803 * ChassisResetAction class supports the POST method for the Reset
804 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700805 * Function handles POST method request.
806 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800807 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700808
809inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800810{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700811 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700812 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700813 .methods(boost::beast::http::verb::post)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000814 std::bind_front(handleChassisResetActionInfoPost, std::ref(app)));
815}
P.K. Leedd99e042020-06-17 19:43:16 +0800816
Nan Zhoucf7eba02022-07-21 23:53:20 +0000817inline void handleChassisResetActionInfoGet(
818 App& app, const crow::Request& req,
819 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
820 const std::string& chassisId)
821{
822 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
823 {
824 return;
825 }
826 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700827 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
828 "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId);
Nan Zhoucf7eba02022-07-21 23:53:20 +0000829 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
P.K. Leedd99e042020-06-17 19:43:16 +0800830
Nan Zhoucf7eba02022-07-21 23:53:20 +0000831 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
832 nlohmann::json::array_t parameters;
833 nlohmann::json::object_t parameter;
834 parameter["Name"] = "ResetType";
835 parameter["Required"] = true;
836 parameter["DataType"] = "String";
837 nlohmann::json::array_t allowed;
Patrick Williamsad539542023-05-12 10:10:08 -0500838 allowed.emplace_back("PowerCycle");
Nan Zhoucf7eba02022-07-21 23:53:20 +0000839 parameter["AllowableValues"] = std::move(allowed);
Patrick Williamsad539542023-05-12 10:10:08 -0500840 parameters.emplace_back(std::move(parameter));
P.K. Leedd99e042020-06-17 19:43:16 +0800841
Nan Zhoucf7eba02022-07-21 23:53:20 +0000842 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700843}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530844
845/**
846 * ChassisResetActionInfo derived class for delivering Chassis
847 * ResetType AllowableValues using ResetInfo schema.
848 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700849inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530850{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700851 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700852 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700853 .methods(boost::beast::http::verb::get)(
Nan Zhoucf7eba02022-07-21 23:53:20 +0000854 std::bind_front(handleChassisResetActionInfoGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700855}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530856
Ed Tanous1abe55e2018-09-05 08:30:59 -0700857} // namespace redfish