blob: cfa1832d8c27c11413535368b91116510828c464 [file] [log] [blame]
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +01001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
James Feistb49ac872019-05-21 15:12:01 -070018#include "health.hpp"
James Feist1c8fba92019-12-20 15:12:07 -080019#include "led.hpp"
Ed Tanous1abe55e2018-09-05 08:30:59 -070020
John Edward Broadbent7e860f12021-04-08 15:57:16 -070021#include <app.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080022#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070023#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070024#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070025#include <sdbusplus/asio/property.hpp>
Gunnar Mills02f6ff12020-10-14 15:59:58 -050026#include <utils/collection.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050027
Ed Tanous1abe55e2018-09-05 08:30:59 -070028namespace redfish
29{
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +010030
31/**
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060032 * @brief Retrieves chassis state properties over dbus
33 *
34 * @param[in] aResp - Shared pointer for completing asynchronous calls.
35 *
36 * @return None.
37 */
zhanghch058d1b46d2021-04-01 11:18:24 +080038inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060039{
Jonathan Doman1e1e5982021-06-11 09:36:17 -070040 // crow::connections::systemBus->async_method_call(
41 sdbusplus::asio::getProperty<std::string>(
42 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
43 "/xyz/openbmc_project/state/chassis0",
44 "xyz.openbmc_project.State.Chassis", "CurrentPowerState",
45 [aResp{std::move(aResp)}](const boost::system::error_code ec,
46 const std::string& chassisState) {
Ed Tanous002d39b2022-05-31 08:59:27 -070047 if (ec)
48 {
49 if (ec == boost::system::errc::host_unreachable)
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060050 {
Ed Tanous002d39b2022-05-31 08:59:27 -070051 // Service not available, no error, just don't return
52 // chassis state info
53 BMCWEB_LOG_DEBUG << "Service not available " << ec;
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060054 return;
55 }
Ed Tanous002d39b2022-05-31 08:59:27 -070056 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
57 messages::internalError(aResp->res);
58 return;
59 }
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060060
Ed Tanous002d39b2022-05-31 08:59:27 -070061 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState;
62 // Verify Chassis State
63 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On")
64 {
65 aResp->res.jsonValue["PowerState"] = "On";
66 aResp->res.jsonValue["Status"]["State"] = "Enabled";
67 }
68 else if (chassisState ==
69 "xyz.openbmc_project.State.Chassis.PowerState.Off")
70 {
71 aResp->res.jsonValue["PowerState"] = "Off";
72 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline";
73 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -070074 });
Gunnar Millsbeeca0a2019-02-14 16:30:45 -060075}
76
zhanghch058d1b46d2021-04-01 11:18:24 +080077inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp,
Ed Tanous23a21a12020-07-25 04:45:05 +000078 const std::string& service,
79 const std::string& objPath)
Qiang XUc1819422019-02-27 13:51:32 +080080{
81 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n";
82
Jonathan Doman1e1e5982021-06-11 09:36:17 -070083 sdbusplus::asio::getProperty<std::string>(
84 *crow::connections::systemBus, service, objPath,
85 "xyz.openbmc_project.Chassis.Intrusion", "Status",
Qiang XUc1819422019-02-27 13:51:32 +080086 [aResp{std::move(aResp)}](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -070087 const std::string& value) {
Ed Tanous002d39b2022-05-31 08:59:27 -070088 if (ec)
89 {
90 // do not add err msg in redfish response, because this is not
91 // mandatory property
92 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n";
93 return;
94 }
Qiang XUc1819422019-02-27 13:51:32 +080095
Ed Tanous002d39b2022-05-31 08:59:27 -070096 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1;
97 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value;
Jonathan Doman1e1e5982021-06-11 09:36:17 -070098 });
Qiang XUc1819422019-02-27 13:51:32 +080099}
100
101/**
102 * Retrieves physical security properties over dbus
103 */
zhanghch058d1b46d2021-04-01 11:18:24 +0800104inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp)
Qiang XUc1819422019-02-27 13:51:32 +0800105{
106 crow::connections::systemBus->async_method_call(
107 [aResp{std::move(aResp)}](
108 const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -0800109 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700110 if (ec)
111 {
112 // do not add err msg in redfish response, because this is not
113 // mandatory property
114 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n";
115 return;
116 }
117 // Iterate over all retrieved ObjectPaths.
118 for (const auto& object : subtree)
119 {
120 for (const auto& service : object.second)
Qiang XUc1819422019-02-27 13:51:32 +0800121 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700122 getIntrusionByService(aResp, service.first, object.first);
Qiang XUc1819422019-02-27 13:51:32 +0800123 return;
124 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700125 }
Qiang XUc1819422019-02-27 13:51:32 +0800126 },
127 "xyz.openbmc_project.ObjectMapper",
128 "/xyz/openbmc_project/object_mapper",
129 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
Ed Tanous271584a2019-07-09 16:24:22 -0700130 "/xyz/openbmc_project/Intrusion", 1,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500131 std::array<const char*, 1>{"xyz.openbmc_project.Chassis.Intrusion"});
Qiang XUc1819422019-02-27 13:51:32 +0800132}
133
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100134/**
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100135 * ChassisCollection derived class for delivering Chassis Collection Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700136 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100137 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700138inline void requestRoutesChassisCollection(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700139{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700140 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/")
Ed Tanoused398212021-06-09 17:05:54 -0700141 .privileges(redfish::privileges::getChassisCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700142 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700143 [&app](const crow::Request& req,
144 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000145 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700146 {
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";
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100153
Ed Tanous002d39b2022-05-31 08:59:27 -0700154 collection_util::getCollectionMembers(
155 asyncResp, "/redfish/v1/Chassis",
156 {"xyz.openbmc_project.Inventory.Item.Board",
157 "xyz.openbmc_project.Inventory.Item.Chassis"});
158 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700159}
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100160
Willy Tu308f70c2021-09-28 20:24:52 -0700161inline void
162 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
163 const std::string& connectionName,
164 const std::string& path)
165{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700166 sdbusplus::asio::getProperty<std::string>(
167 *crow::connections::systemBus, connectionName, path,
168 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
Willy Tu308f70c2021-09-28 20:24:52 -0700169 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700170 const std::string& property) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700171 if (ec)
172 {
173 BMCWEB_LOG_DEBUG << "DBUS response error for Location";
174 messages::internalError(asyncResp->res);
175 return;
176 }
Willy Tu308f70c2021-09-28 20:24:52 -0700177
Ed Tanous002d39b2022-05-31 08:59:27 -0700178 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
179 property;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700180 });
Willy Tu308f70c2021-09-28 20:24:52 -0700181}
182
183inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
184 const std::string& connectionName,
185 const std::string& path)
186{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700187 sdbusplus::asio::getProperty<std::string>(
188 *crow::connections::systemBus, connectionName, path,
189 "xyz.openbmc_project.Common.UUID", "UUID",
Willy Tu308f70c2021-09-28 20:24:52 -0700190 [asyncResp](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700191 const std::string& chassisUUID) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700192 if (ec)
193 {
194 BMCWEB_LOG_DEBUG << "DBUS response error for UUID";
195 messages::internalError(asyncResp->res);
196 return;
197 }
198 asyncResp->res.jsonValue["UUID"] = chassisUUID;
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700199 });
Willy Tu308f70c2021-09-28 20:24:52 -0700200}
201
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100202/**
203 * Chassis override class for delivering Chassis Schema
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700204 * Functions triggers appropriate requests on DBus
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100205 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700206inline void requestRoutesChassis(App& app)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700207{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700208 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700209 .privileges(redfish::privileges::getChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700210 .methods(boost::beast::http::verb::get)(
211 [&app](const crow::Request& req,
212 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
213 const std::string& chassisId) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000214 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700215 {
216 return;
217 }
218 const std::array<const char*, 2> interfaces = {
219 "xyz.openbmc_project.Inventory.Item.Board",
220 "xyz.openbmc_project.Inventory.Item.Chassis"};
221
222 crow::connections::systemBus->async_method_call(
223 [asyncResp, chassisId(std::string(chassisId))](
224 const boost::system::error_code ec,
225 const dbus::utility::MapperGetSubTreeResponse& subtree) {
226 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700227 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700228 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700229 return;
230 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700231 // Iterate over all retrieved ObjectPaths.
232 for (const std::pair<std::string,
233 std::vector<std::pair<
234 std::string, std::vector<std::string>>>>&
235 object : subtree)
236 {
237 const std::string& path = object.first;
238 const std::vector<
239 std::pair<std::string, std::vector<std::string>>>&
240 connectionNames = object.second;
Rapkiewicz, Pawele37f8452018-03-09 13:49:50 +0100241
Ed Tanous002d39b2022-05-31 08:59:27 -0700242 sdbusplus::message::object_path objPath(path);
243 if (objPath.filename() != chassisId)
244 {
245 continue;
246 }
247
248 auto health = std::make_shared<HealthPopulate>(asyncResp);
249
250 sdbusplus::asio::getProperty<std::vector<std::string>>(
251 *crow::connections::systemBus,
252 "xyz.openbmc_project.ObjectMapper", path + "/all_sensors",
253 "xyz.openbmc_project.Association", "endpoints",
254 [health](const boost::system::error_code ec2,
255 const std::vector<std::string>& resp) {
256 if (ec2)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700257 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700258 return; // no sensors = no failures
Ed Tanousdaf36e22018-04-20 16:01:36 -0700259 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700260 health->inventory = resp;
261 });
262
263 health->populate();
264
265 if (connectionNames.empty())
266 {
267 BMCWEB_LOG_ERROR << "Got 0 Connection names";
268 continue;
269 }
270
271 asyncResp->res.jsonValue["@odata.type"] =
272 "#Chassis.v1_16_0.Chassis";
273 asyncResp->res.jsonValue["@odata.id"] =
274 "/redfish/v1/Chassis/" + chassisId;
275 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
276 asyncResp->res.jsonValue["ChassisType"] = "RackMount";
277 asyncResp->res
278 .jsonValue["Actions"]["#Chassis.Reset"]["target"] =
279 "/redfish/v1/Chassis/" + chassisId +
280 "/Actions/Chassis.Reset";
281 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]
282 ["@Redfish.ActionInfo"] =
283 "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
284 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] =
285 "/redfish/v1/Systems/system/PCIeDevices";
286
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700287 sdbusplus::asio::getProperty<std::vector<std::string>>(
288 *crow::connections::systemBus,
289 "xyz.openbmc_project.ObjectMapper", path + "/drive",
290 "xyz.openbmc_project.Association", "endpoints",
291 [asyncResp,
292 chassisId](const boost::system::error_code ec3,
293 const std::vector<std::string>& resp) {
294 if (ec3 || resp.empty())
295 {
296 return; // no drives = no failures
297 }
298
299 nlohmann::json reference;
300 reference["odata.id"] = crow::utility::urlFromPieces(
301 "redfish", "v1", "Chassis", chassisId, "Drives");
302 asyncResp->res.jsonValue["Drives"] = std::move(reference);
303 });
304
Ed Tanous002d39b2022-05-31 08:59:27 -0700305 const std::string& connectionName = connectionNames[0].first;
306
307 const std::vector<std::string>& interfaces2 =
308 connectionNames[0].second;
309 const std::array<const char*, 2> hasIndicatorLed = {
310 "xyz.openbmc_project.Inventory.Item.Panel",
311 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
312
313 const std::string assetTagInterface =
314 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
315 if (std::find(interfaces2.begin(), interfaces2.end(),
316 assetTagInterface) != interfaces2.end())
317 {
318 sdbusplus::asio::getProperty<std::string>(
319 *crow::connections::systemBus, connectionName, path,
320 assetTagInterface, "AssetTag",
321 [asyncResp, chassisId(std::string(chassisId))](
Ed Tanous8a592812022-06-04 09:06:59 -0700322 const boost::system::error_code ec2,
Ed Tanous002d39b2022-05-31 08:59:27 -0700323 const std::string& property) {
Ed Tanous8a592812022-06-04 09:06:59 -0700324 if (ec2)
Ed Tanous002d39b2022-05-31 08:59:27 -0700325 {
326 BMCWEB_LOG_DEBUG
327 << "DBus response error for AssetTag";
328 messages::internalError(asyncResp->res);
329 return;
330 }
331 asyncResp->res.jsonValue["AssetTag"] = property;
332 });
333 }
334
335 for (const char* interface : hasIndicatorLed)
336 {
337 if (std::find(interfaces2.begin(), interfaces2.end(),
338 interface) != interfaces2.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700339 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 getIndicatorLedState(asyncResp);
341 getLocationIndicatorActive(asyncResp);
342 break;
343 }
344 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700345
Ed Tanous002d39b2022-05-31 08:59:27 -0700346 crow::connections::systemBus->async_method_call(
347 [asyncResp, chassisId(std::string(chassisId))](
348 const boost::system::error_code /*ec2*/,
349 const dbus::utility::DBusPropertiesMap&
350 propertiesList) {
351 for (const std::pair<std::string,
Ed Tanous168e20c2021-12-13 14:39:53 -0800352 dbus::utility::DbusVariantType>&
Ed Tanous002d39b2022-05-31 08:59:27 -0700353 property : propertiesList)
354 {
355 // Store DBus properties that are also
356 // Redfish properties with same name and a
357 // string value
358 const std::string& propertyName = property.first;
359 if ((propertyName == "PartNumber") ||
360 (propertyName == "SerialNumber") ||
361 (propertyName == "Manufacturer") ||
362 (propertyName == "Model") ||
363 (propertyName == "SparePartNumber"))
Sharad Yadav2c37b4b2021-05-10 12:53:38 +0530364 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700365 const std::string* value =
366 std::get_if<std::string>(&property.second);
367 if (value == nullptr)
Willy Tu308f70c2021-09-28 20:24:52 -0700368 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700369 BMCWEB_LOG_ERROR << "Null value returned for "
370 << propertyName;
371 messages::internalError(asyncResp->res);
372 return;
Willy Tu308f70c2021-09-28 20:24:52 -0700373 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700374 // SparePartNumber is optional on D-Bus
375 // so skip if it is empty
376 if (propertyName == "SparePartNumber")
Willy Tu308f70c2021-09-28 20:24:52 -0700377 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700378 if (value->empty())
379 {
380 continue;
381 }
Willy Tu308f70c2021-09-28 20:24:52 -0700382 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700383 asyncResp->res.jsonValue[propertyName] = *value;
Sharad Yadav2c37b4b2021-05-10 12:53:38 +0530384 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700385 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700386 asyncResp->res.jsonValue["Name"] = chassisId;
387 asyncResp->res.jsonValue["Id"] = chassisId;
388#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
389 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
390 "/redfish/v1/Chassis/" + chassisId + "/Thermal";
391 // Power object
392 asyncResp->res.jsonValue["Power"]["@odata.id"] =
393 "/redfish/v1/Chassis/" + chassisId + "/Power";
394#endif
395 // SensorCollection
396 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
397 "/redfish/v1/Chassis/" + chassisId + "/Sensors";
398 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700399
Ed Tanous002d39b2022-05-31 08:59:27 -0700400 nlohmann::json::array_t computerSystems;
401 nlohmann::json::object_t system;
402 system["@odata.id"] = "/redfish/v1/Systems/system";
403 computerSystems.push_back(std::move(system));
404 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
405 std::move(computerSystems);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700406
Ed Tanous002d39b2022-05-31 08:59:27 -0700407 nlohmann::json::array_t managedBy;
408 nlohmann::json::object_t manager;
409 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
410 managedBy.push_back(std::move(manager));
411 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
412 std::move(managedBy);
413 getChassisState(asyncResp);
414 },
415 connectionName, path, "org.freedesktop.DBus.Properties",
416 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
417
418 for (const auto& interface : interfaces2)
419 {
420 if (interface == "xyz.openbmc_project.Common.UUID")
421 {
422 getChassisUUID(asyncResp, connectionName, path);
423 }
424 else if (
425 interface ==
426 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
427 {
428 getChassisLocationCode(asyncResp, connectionName, path);
429 }
430 }
431
432 return;
433 }
434
435 // Couldn't find an object with that name. return an error
436 messages::resourceNotFound(asyncResp->res,
437 "#Chassis.v1_16_0.Chassis", chassisId);
438 },
439 "xyz.openbmc_project.ObjectMapper",
440 "/xyz/openbmc_project/object_mapper",
441 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
442 "/xyz/openbmc_project/inventory", 0, interfaces);
443
444 getPhysicalSecurityData(asyncResp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700445 });
446
447 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700448 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700449 .methods(boost::beast::http::verb::patch)(
450 [&app](const crow::Request& req,
451 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
452 const std::string& param) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000453 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700454 {
455 return;
456 }
457 std::optional<bool> locationIndicatorActive;
458 std::optional<std::string> indicatorLed;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700459
Ed Tanous002d39b2022-05-31 08:59:27 -0700460 if (param.empty())
461 {
462 return;
463 }
464
465 if (!json_util::readJsonPatch(
466 req, asyncResp->res, "LocationIndicatorActive",
467 locationIndicatorActive, "IndicatorLED", indicatorLed))
468 {
469 return;
470 }
471
472 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
473 if (!locationIndicatorActive && !indicatorLed)
474 {
475 return; // delete this when we support more patch properties
476 }
477 if (indicatorLed)
478 {
479 asyncResp->res.addHeader(
480 boost::beast::http::field::warning,
481 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
482 }
483
484 const std::array<const char*, 2> interfaces = {
485 "xyz.openbmc_project.Inventory.Item.Board",
486 "xyz.openbmc_project.Inventory.Item.Chassis"};
487
488 const std::string& chassisId = param;
489
490 crow::connections::systemBus->async_method_call(
491 [asyncResp, chassisId, locationIndicatorActive, indicatorLed](
492 const boost::system::error_code ec,
493 const dbus::utility::MapperGetSubTreeResponse& subtree) {
494 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700495 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700496 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700497 return;
498 }
499
Ed Tanous002d39b2022-05-31 08:59:27 -0700500 // Iterate over all retrieved ObjectPaths.
501 for (const std::pair<std::string,
502 std::vector<std::pair<
503 std::string, std::vector<std::string>>>>&
504 object : subtree)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 const std::string& path = object.first;
507 const std::vector<
508 std::pair<std::string, std::vector<std::string>>>&
509 connectionNames = object.second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700510
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 sdbusplus::message::object_path objPath(path);
512 if (objPath.filename() != chassisId)
513 {
514 continue;
515 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700516
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 if (connectionNames.empty())
518 {
519 BMCWEB_LOG_ERROR << "Got 0 Connection names";
520 continue;
521 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700522
Ed Tanous002d39b2022-05-31 08:59:27 -0700523 const std::vector<std::string>& interfaces3 =
524 connectionNames[0].second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700525
Ed Tanous002d39b2022-05-31 08:59:27 -0700526 const std::array<const char*, 2> hasIndicatorLed = {
527 "xyz.openbmc_project.Inventory.Item.Panel",
528 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
529 bool indicatorChassis = false;
530 for (const char* interface : hasIndicatorLed)
531 {
532 if (std::find(interfaces3.begin(), interfaces3.end(),
533 interface) != interfaces3.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700534 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 indicatorChassis = true;
536 break;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700537 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700538 }
539 if (locationIndicatorActive)
540 {
541 if (indicatorChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700542 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700543 setLocationIndicatorActive(asyncResp,
544 *locationIndicatorActive);
James Feist1c8fba92019-12-20 15:12:07 -0800545 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700546 else
547 {
548 messages::propertyUnknown(asyncResp->res,
549 "LocationIndicatorActive");
550 }
551 }
552 if (indicatorLed)
553 {
554 if (indicatorChassis)
555 {
556 setIndicatorLedState(asyncResp, *indicatorLed);
557 }
558 else
559 {
560 messages::propertyUnknown(asyncResp->res,
561 "IndicatorLED");
562 }
563 }
564 return;
565 }
James Feist1c8fba92019-12-20 15:12:07 -0800566
Ed Tanous002d39b2022-05-31 08:59:27 -0700567 messages::resourceNotFound(asyncResp->res,
568 "#Chassis.v1_14_0.Chassis", chassisId);
569 },
570 "xyz.openbmc_project.ObjectMapper",
571 "/xyz/openbmc_project/object_mapper",
572 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
573 "/xyz/openbmc_project/inventory", 0, interfaces);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700574 });
575}
P.K. Leedd99e042020-06-17 19:43:16 +0800576
zhanghch058d1b46d2021-04-01 11:18:24 +0800577inline void
578 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800579{
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700580 const char* busName = "xyz.openbmc_project.ObjectMapper";
581 const char* path = "/xyz/openbmc_project/object_mapper";
582 const char* interface = "xyz.openbmc_project.ObjectMapper";
583 const char* method = "GetSubTreePaths";
P.K. Leedd99e042020-06-17 19:43:16 +0800584
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700585 const std::array<const char*, 1> interfaces = {
586 "xyz.openbmc_project.State.Chassis"};
587
588 // Use mapper to get subtree paths.
P.K. Leedd99e042020-06-17 19:43:16 +0800589 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800590 [asyncResp](
591 const boost::system::error_code ec,
592 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700593 if (ec)
594 {
595 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
596 messages::internalError(asyncResp->res);
597 return;
598 }
599
600 const char* processName = "xyz.openbmc_project.State.Chassis";
601 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
602 const char* destProperty = "RequestedPowerTransition";
603 const std::string propertyValue =
604 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
605 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
606
607 /* Look for system reset chassis path */
608 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
609 chassisList.end())
610 {
611 /* We prefer to reset the full chassis_system, but if it doesn't
612 * exist on some platforms, fall back to a host-only power reset
613 */
614 objectPath = "/xyz/openbmc_project/state/chassis0";
615 }
616
617 crow::connections::systemBus->async_method_call(
Ed Tanous8a592812022-06-04 09:06:59 -0700618 [asyncResp](const boost::system::error_code ec2) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700619 // Use "Set" method to set the property value.
Ed Tanous8a592812022-06-04 09:06:59 -0700620 if (ec2)
P.K. Leedd99e042020-06-17 19:43:16 +0800621 {
Ed Tanous8a592812022-06-04 09:06:59 -0700622 BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec2;
P.K. Leedd99e042020-06-17 19:43:16 +0800623 messages::internalError(asyncResp->res);
624 return;
625 }
626
Ed Tanous002d39b2022-05-31 08:59:27 -0700627 messages::success(asyncResp->res);
628 },
629 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
630 interfaceName, destProperty,
631 dbus::utility::DbusVariantType{propertyValue});
P.K. Leedd99e042020-06-17 19:43:16 +0800632 },
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700633 busName, path, interface, method, "/", 0, interfaces);
P.K. Leedd99e042020-06-17 19:43:16 +0800634}
635
636/**
637 * ChassisResetAction class supports the POST method for the Reset
638 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700639 * Function handles POST method request.
640 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800641 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700642
643inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800644{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700645 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700646 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700647 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700648 [&app](const crow::Request& req,
649 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
650 const std::string&) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000651 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 {
653 return;
654 }
655 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
P.K. Leedd99e042020-06-17 19:43:16 +0800656
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 std::string resetType;
P.K. Leedd99e042020-06-17 19:43:16 +0800658
Ed Tanous002d39b2022-05-31 08:59:27 -0700659 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
660 resetType))
661 {
662 return;
663 }
P.K. Leedd99e042020-06-17 19:43:16 +0800664
Ed Tanous002d39b2022-05-31 08:59:27 -0700665 if (resetType != "PowerCycle")
666 {
667 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
668 << resetType;
669 messages::actionParameterNotSupported(asyncResp->res, resetType,
670 "ResetType");
P.K. Leedd99e042020-06-17 19:43:16 +0800671
Ed Tanous002d39b2022-05-31 08:59:27 -0700672 return;
673 }
674 doChassisPowerCycle(asyncResp);
675 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700676}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530677
678/**
679 * ChassisResetActionInfo derived class for delivering Chassis
680 * ResetType AllowableValues using ResetInfo schema.
681 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700682inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530683{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700684 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700685 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700686 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700687 [&app](const crow::Request& req,
688 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
689 const std::string& chassisId) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000690 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700691 {
692 return;
693 }
694 asyncResp->res.jsonValue["@odata.type"] =
695 "#ActionInfo.v1_1_2.ActionInfo";
696 asyncResp->res.jsonValue["@odata.id"] =
697 "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
698 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
Ed Tanous14766872022-03-15 10:44:42 -0700699
Ed Tanous002d39b2022-05-31 08:59:27 -0700700 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
Nan Zhou5b9e95a2022-06-01 17:12:23 +0000701 nlohmann::json::array_t parameters;
702 nlohmann::json::object_t parameter;
703 parameter["Name"] = "ResetType";
704 parameter["Required"] = true;
705 parameter["DataType"] = "String";
Ed Tanous002d39b2022-05-31 08:59:27 -0700706 nlohmann::json::array_t allowed;
707 allowed.push_back("PowerCycle");
Nan Zhou5b9e95a2022-06-01 17:12:23 +0000708 parameter["AllowableValues"] = std::move(allowed);
709 parameters.push_back(std::move(parameter));
710
Ed Tanous002d39b2022-05-31 08:59:27 -0700711 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
712 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700713}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530714
Ed Tanous1abe55e2018-09-05 08:30:59 -0700715} // namespace redfish