blob: 29615132c741ca92fb6920a37efd0e43dad93b06 [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) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700145 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
146 {
147 return;
148 }
149 asyncResp->res.jsonValue["@odata.type"] =
150 "#ChassisCollection.ChassisCollection";
151 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis";
152 asyncResp->res.jsonValue["Name"] = "Chassis Collection";
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) {
214 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
215 {
216 return;
217 }
218 const std::array<const char*, 2> interfaces = {
219 "xyz.openbmc_project.Inventory.Item.Board",
220 "xyz.openbmc_project.Inventory.Item.Chassis"};
221
222 crow::connections::systemBus->async_method_call(
223 [asyncResp, chassisId(std::string(chassisId))](
224 const boost::system::error_code ec,
225 const dbus::utility::MapperGetSubTreeResponse& subtree) {
226 if (ec)
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
287 const std::string& connectionName = connectionNames[0].first;
288
289 const std::vector<std::string>& interfaces2 =
290 connectionNames[0].second;
291 const std::array<const char*, 2> hasIndicatorLed = {
292 "xyz.openbmc_project.Inventory.Item.Panel",
293 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
294
295 const std::string assetTagInterface =
296 "xyz.openbmc_project.Inventory.Decorator.AssetTag";
297 if (std::find(interfaces2.begin(), interfaces2.end(),
298 assetTagInterface) != interfaces2.end())
299 {
300 sdbusplus::asio::getProperty<std::string>(
301 *crow::connections::systemBus, connectionName, path,
302 assetTagInterface, "AssetTag",
303 [asyncResp, chassisId(std::string(chassisId))](
304 const boost::system::error_code ec,
305 const std::string& property) {
306 if (ec)
307 {
308 BMCWEB_LOG_DEBUG
309 << "DBus response error for AssetTag";
310 messages::internalError(asyncResp->res);
311 return;
312 }
313 asyncResp->res.jsonValue["AssetTag"] = property;
314 });
315 }
316
317 for (const char* interface : hasIndicatorLed)
318 {
319 if (std::find(interfaces2.begin(), interfaces2.end(),
320 interface) != interfaces2.end())
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 getIndicatorLedState(asyncResp);
323 getLocationIndicatorActive(asyncResp);
324 break;
325 }
326 }
Ed Tanouse0d918b2018-03-27 17:41:04 -0700327
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 crow::connections::systemBus->async_method_call(
329 [asyncResp, chassisId(std::string(chassisId))](
330 const boost::system::error_code /*ec2*/,
331 const dbus::utility::DBusPropertiesMap&
332 propertiesList) {
333 for (const std::pair<std::string,
Ed Tanous168e20c2021-12-13 14:39:53 -0800334 dbus::utility::DbusVariantType>&
Ed Tanous002d39b2022-05-31 08:59:27 -0700335 property : propertiesList)
336 {
337 // Store DBus properties that are also
338 // Redfish properties with same name and a
339 // string value
340 const std::string& propertyName = property.first;
341 if ((propertyName == "PartNumber") ||
342 (propertyName == "SerialNumber") ||
343 (propertyName == "Manufacturer") ||
344 (propertyName == "Model") ||
345 (propertyName == "SparePartNumber"))
Sharad Yadav2c37b4b2021-05-10 12:53:38 +0530346 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700347 const std::string* value =
348 std::get_if<std::string>(&property.second);
349 if (value == nullptr)
Willy Tu308f70c2021-09-28 20:24:52 -0700350 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700351 BMCWEB_LOG_ERROR << "Null value returned for "
352 << propertyName;
353 messages::internalError(asyncResp->res);
354 return;
Willy Tu308f70c2021-09-28 20:24:52 -0700355 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700356 // SparePartNumber is optional on D-Bus
357 // so skip if it is empty
358 if (propertyName == "SparePartNumber")
Willy Tu308f70c2021-09-28 20:24:52 -0700359 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700360 if (value->empty())
361 {
362 continue;
363 }
Willy Tu308f70c2021-09-28 20:24:52 -0700364 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700365 asyncResp->res.jsonValue[propertyName] = *value;
Sharad Yadav2c37b4b2021-05-10 12:53:38 +0530366 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700367 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700368 asyncResp->res.jsonValue["Name"] = chassisId;
369 asyncResp->res.jsonValue["Id"] = chassisId;
370#ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL
371 asyncResp->res.jsonValue["Thermal"]["@odata.id"] =
372 "/redfish/v1/Chassis/" + chassisId + "/Thermal";
373 // Power object
374 asyncResp->res.jsonValue["Power"]["@odata.id"] =
375 "/redfish/v1/Chassis/" + chassisId + "/Power";
376#endif
377 // SensorCollection
378 asyncResp->res.jsonValue["Sensors"]["@odata.id"] =
379 "/redfish/v1/Chassis/" + chassisId + "/Sensors";
380 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700381
Ed Tanous002d39b2022-05-31 08:59:27 -0700382 nlohmann::json::array_t computerSystems;
383 nlohmann::json::object_t system;
384 system["@odata.id"] = "/redfish/v1/Systems/system";
385 computerSystems.push_back(std::move(system));
386 asyncResp->res.jsonValue["Links"]["ComputerSystems"] =
387 std::move(computerSystems);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700388
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 nlohmann::json::array_t managedBy;
390 nlohmann::json::object_t manager;
391 manager["@odata.id"] = "/redfish/v1/Managers/bmc";
392 managedBy.push_back(std::move(manager));
393 asyncResp->res.jsonValue["Links"]["ManagedBy"] =
394 std::move(managedBy);
395 getChassisState(asyncResp);
396 },
397 connectionName, path, "org.freedesktop.DBus.Properties",
398 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
399
400 for (const auto& interface : interfaces2)
401 {
402 if (interface == "xyz.openbmc_project.Common.UUID")
403 {
404 getChassisUUID(asyncResp, connectionName, path);
405 }
406 else if (
407 interface ==
408 "xyz.openbmc_project.Inventory.Decorator.LocationCode")
409 {
410 getChassisLocationCode(asyncResp, connectionName, path);
411 }
412 }
413
414 return;
415 }
416
417 // Couldn't find an object with that name. return an error
418 messages::resourceNotFound(asyncResp->res,
419 "#Chassis.v1_16_0.Chassis", chassisId);
420 },
421 "xyz.openbmc_project.ObjectMapper",
422 "/xyz/openbmc_project/object_mapper",
423 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
424 "/xyz/openbmc_project/inventory", 0, interfaces);
425
426 getPhysicalSecurityData(asyncResp);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700427 });
428
429 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700430 .privileges(redfish::privileges::patchChassis)
Ed Tanous002d39b2022-05-31 08:59:27 -0700431 .methods(boost::beast::http::verb::patch)(
432 [&app](const crow::Request& req,
433 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
434 const std::string& param) {
435 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
436 {
437 return;
438 }
439 std::optional<bool> locationIndicatorActive;
440 std::optional<std::string> indicatorLed;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700441
Ed Tanous002d39b2022-05-31 08:59:27 -0700442 if (param.empty())
443 {
444 return;
445 }
446
447 if (!json_util::readJsonPatch(
448 req, asyncResp->res, "LocationIndicatorActive",
449 locationIndicatorActive, "IndicatorLED", indicatorLed))
450 {
451 return;
452 }
453
454 // TODO (Gunnar): Remove IndicatorLED after enough time has passed
455 if (!locationIndicatorActive && !indicatorLed)
456 {
457 return; // delete this when we support more patch properties
458 }
459 if (indicatorLed)
460 {
461 asyncResp->res.addHeader(
462 boost::beast::http::field::warning,
463 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\"");
464 }
465
466 const std::array<const char*, 2> interfaces = {
467 "xyz.openbmc_project.Inventory.Item.Board",
468 "xyz.openbmc_project.Inventory.Item.Chassis"};
469
470 const std::string& chassisId = param;
471
472 crow::connections::systemBus->async_method_call(
473 [asyncResp, chassisId, locationIndicatorActive, indicatorLed](
474 const boost::system::error_code ec,
475 const dbus::utility::MapperGetSubTreeResponse& subtree) {
476 if (ec)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700477 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 messages::internalError(asyncResp->res);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700479 return;
480 }
481
Ed Tanous002d39b2022-05-31 08:59:27 -0700482 // Iterate over all retrieved ObjectPaths.
483 for (const std::pair<std::string,
484 std::vector<std::pair<
485 std::string, std::vector<std::string>>>>&
486 object : subtree)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700487 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 const std::string& path = object.first;
489 const std::vector<
490 std::pair<std::string, std::vector<std::string>>>&
491 connectionNames = object.second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 sdbusplus::message::object_path objPath(path);
494 if (objPath.filename() != chassisId)
495 {
496 continue;
497 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700498
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 if (connectionNames.empty())
500 {
501 BMCWEB_LOG_ERROR << "Got 0 Connection names";
502 continue;
503 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700504
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 const std::vector<std::string>& interfaces3 =
506 connectionNames[0].second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700507
Ed Tanous002d39b2022-05-31 08:59:27 -0700508 const std::array<const char*, 2> hasIndicatorLed = {
509 "xyz.openbmc_project.Inventory.Item.Panel",
510 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
511 bool indicatorChassis = false;
512 for (const char* interface : hasIndicatorLed)
513 {
514 if (std::find(interfaces3.begin(), interfaces3.end(),
515 interface) != interfaces3.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700516 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 indicatorChassis = true;
518 break;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700519 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 }
521 if (locationIndicatorActive)
522 {
523 if (indicatorChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700524 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700525 setLocationIndicatorActive(asyncResp,
526 *locationIndicatorActive);
James Feist1c8fba92019-12-20 15:12:07 -0800527 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 else
529 {
530 messages::propertyUnknown(asyncResp->res,
531 "LocationIndicatorActive");
532 }
533 }
534 if (indicatorLed)
535 {
536 if (indicatorChassis)
537 {
538 setIndicatorLedState(asyncResp, *indicatorLed);
539 }
540 else
541 {
542 messages::propertyUnknown(asyncResp->res,
543 "IndicatorLED");
544 }
545 }
546 return;
547 }
James Feist1c8fba92019-12-20 15:12:07 -0800548
Ed Tanous002d39b2022-05-31 08:59:27 -0700549 messages::resourceNotFound(asyncResp->res,
550 "#Chassis.v1_14_0.Chassis", chassisId);
551 },
552 "xyz.openbmc_project.ObjectMapper",
553 "/xyz/openbmc_project/object_mapper",
554 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
555 "/xyz/openbmc_project/inventory", 0, interfaces);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700556 });
557}
P.K. Leedd99e042020-06-17 19:43:16 +0800558
zhanghch058d1b46d2021-04-01 11:18:24 +0800559inline void
560 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
P.K. Leedd99e042020-06-17 19:43:16 +0800561{
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700562 const char* busName = "xyz.openbmc_project.ObjectMapper";
563 const char* path = "/xyz/openbmc_project/object_mapper";
564 const char* interface = "xyz.openbmc_project.ObjectMapper";
565 const char* method = "GetSubTreePaths";
P.K. Leedd99e042020-06-17 19:43:16 +0800566
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700567 const std::array<const char*, 1> interfaces = {
568 "xyz.openbmc_project.State.Chassis"};
569
570 // Use mapper to get subtree paths.
P.K. Leedd99e042020-06-17 19:43:16 +0800571 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800572 [asyncResp](
573 const boost::system::error_code ec,
574 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700575 if (ec)
576 {
577 BMCWEB_LOG_DEBUG << "[mapper] Bad D-Bus request error: " << ec;
578 messages::internalError(asyncResp->res);
579 return;
580 }
581
582 const char* processName = "xyz.openbmc_project.State.Chassis";
583 const char* interfaceName = "xyz.openbmc_project.State.Chassis";
584 const char* destProperty = "RequestedPowerTransition";
585 const std::string propertyValue =
586 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
587 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0";
588
589 /* Look for system reset chassis path */
590 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) ==
591 chassisList.end())
592 {
593 /* We prefer to reset the full chassis_system, but if it doesn't
594 * exist on some platforms, fall back to a host-only power reset
595 */
596 objectPath = "/xyz/openbmc_project/state/chassis0";
597 }
598
599 crow::connections::systemBus->async_method_call(
600 [asyncResp](const boost::system::error_code ec) {
601 // Use "Set" method to set the property value.
P.K. Leedd99e042020-06-17 19:43:16 +0800602 if (ec)
603 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700604 BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec;
P.K. Leedd99e042020-06-17 19:43:16 +0800605 messages::internalError(asyncResp->res);
606 return;
607 }
608
Ed Tanous002d39b2022-05-31 08:59:27 -0700609 messages::success(asyncResp->res);
610 },
611 processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
612 interfaceName, destProperty,
613 dbus::utility::DbusVariantType{propertyValue});
P.K. Leedd99e042020-06-17 19:43:16 +0800614 },
Vijay Khemkac3b3c922020-09-22 23:00:12 -0700615 busName, path, interface, method, "/", 0, interfaces);
P.K. Leedd99e042020-06-17 19:43:16 +0800616}
617
618/**
619 * ChassisResetAction class supports the POST method for the Reset
620 * action.
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700621 * Function handles POST method request.
622 * Analyzes POST body before sending Reset request data to D-Bus.
P.K. Leedd99e042020-06-17 19:43:16 +0800623 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700624
625inline void requestRoutesChassisResetAction(App& app)
P.K. Leedd99e042020-06-17 19:43:16 +0800626{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700627 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/")
Ed Tanoused398212021-06-09 17:05:54 -0700628 .privileges(redfish::privileges::postChassis)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700629 .methods(boost::beast::http::verb::post)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700630 [&app](const crow::Request& req,
631 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
632 const std::string&) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
634 {
635 return;
636 }
637 BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
P.K. Leedd99e042020-06-17 19:43:16 +0800638
Ed Tanous002d39b2022-05-31 08:59:27 -0700639 std::string resetType;
P.K. Leedd99e042020-06-17 19:43:16 +0800640
Ed Tanous002d39b2022-05-31 08:59:27 -0700641 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
642 resetType))
643 {
644 return;
645 }
P.K. Leedd99e042020-06-17 19:43:16 +0800646
Ed Tanous002d39b2022-05-31 08:59:27 -0700647 if (resetType != "PowerCycle")
648 {
649 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
650 << resetType;
651 messages::actionParameterNotSupported(asyncResp->res, resetType,
652 "ResetType");
P.K. Leedd99e042020-06-17 19:43:16 +0800653
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 return;
655 }
656 doChassisPowerCycle(asyncResp);
657 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700658}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530659
660/**
661 * ChassisResetActionInfo derived class for delivering Chassis
662 * ResetType AllowableValues using ResetInfo schema.
663 */
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700664inline void requestRoutesChassisResetActionInfo(App& app)
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530665{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700666 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/")
Ed Tanoused398212021-06-09 17:05:54 -0700667 .privileges(redfish::privileges::getActionInfo)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700668 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -0700669 [&app](const crow::Request& req,
670 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
671 const std::string& chassisId) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700672 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
673 {
674 return;
675 }
676 asyncResp->res.jsonValue["@odata.type"] =
677 "#ActionInfo.v1_1_2.ActionInfo";
678 asyncResp->res.jsonValue["@odata.id"] =
679 "/redfish/v1/Chassis/" + chassisId + "/ResetActionInfo";
680 asyncResp->res.jsonValue["Name"] = "Reset Action Info";
Ed Tanous14766872022-03-15 10:44:42 -0700681
Ed Tanous002d39b2022-05-31 08:59:27 -0700682 asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
683 nlohmann::json::object_t parameters;
684 parameters["Name"] = "ResetType";
685 parameters["Required"] = true;
686 parameters["DataType"] = "String";
687 nlohmann::json::array_t allowed;
688 allowed.push_back("PowerCycle");
689 parameters["AllowableValues"] = std::move(allowed);
690 asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
691 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700692}
AppaRao Puli1cb1a9e2020-07-17 23:38:57 +0530693
Ed Tanous1abe55e2018-09-05 08:30:59 -0700694} // namespace redfish