1 /* 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 18 #include "bmcweb_config.h" 19 20 #include "app.hpp" 21 #include "dbus_utility.hpp" 22 #include "health.hpp" 23 #include "led.hpp" 24 #include "query.hpp" 25 #include "registries/privilege_registry.hpp" 26 #include "utils/collection.hpp" 27 #include "utils/dbus_utils.hpp" 28 #include "utils/json_utils.hpp" 29 30 #include <boost/system/error_code.hpp> 31 #include <boost/url/format.hpp> 32 #include <sdbusplus/asio/property.hpp> 33 #include <sdbusplus/unpack_properties.hpp> 34 35 #include <array> 36 #include <string_view> 37 38 namespace redfish 39 { 40 41 /** 42 * @brief Retrieves chassis state properties over dbus 43 * 44 * @param[in] aResp - Shared pointer for completing asynchronous calls. 45 * 46 * @return None. 47 */ 48 inline void getChassisState(std::shared_ptr<bmcweb::AsyncResp> aResp) 49 { 50 // crow::connections::systemBus->async_method_call( 51 sdbusplus::asio::getProperty<std::string>( 52 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 53 "/xyz/openbmc_project/state/chassis0", 54 "xyz.openbmc_project.State.Chassis", "CurrentPowerState", 55 [aResp{std::move(aResp)}](const boost::system::error_code& ec, 56 const std::string& chassisState) { 57 if (ec) 58 { 59 if (ec == boost::system::errc::host_unreachable) 60 { 61 // Service not available, no error, just don't return 62 // chassis state info 63 BMCWEB_LOG_DEBUG << "Service not available " << ec; 64 return; 65 } 66 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 67 messages::internalError(aResp->res); 68 return; 69 } 70 71 BMCWEB_LOG_DEBUG << "Chassis state: " << chassisState; 72 // Verify Chassis State 73 if (chassisState == "xyz.openbmc_project.State.Chassis.PowerState.On") 74 { 75 aResp->res.jsonValue["PowerState"] = "On"; 76 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 77 } 78 else if (chassisState == 79 "xyz.openbmc_project.State.Chassis.PowerState.Off") 80 { 81 aResp->res.jsonValue["PowerState"] = "Off"; 82 aResp->res.jsonValue["Status"]["State"] = "StandbyOffline"; 83 } 84 }); 85 } 86 87 inline void getIntrusionByService(std::shared_ptr<bmcweb::AsyncResp> aResp, 88 const std::string& service, 89 const std::string& objPath) 90 { 91 BMCWEB_LOG_DEBUG << "Get intrusion status by service \n"; 92 93 sdbusplus::asio::getProperty<std::string>( 94 *crow::connections::systemBus, service, objPath, 95 "xyz.openbmc_project.Chassis.Intrusion", "Status", 96 [aResp{std::move(aResp)}](const boost::system::error_code& ec, 97 const std::string& value) { 98 if (ec) 99 { 100 // do not add err msg in redfish response, because this is not 101 // mandatory property 102 BMCWEB_LOG_ERROR << "DBUS response error " << ec << "\n"; 103 return; 104 } 105 106 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensorNumber"] = 1; 107 aResp->res.jsonValue["PhysicalSecurity"]["IntrusionSensor"] = value; 108 }); 109 } 110 111 /** 112 * Retrieves physical security properties over dbus 113 */ 114 inline void getPhysicalSecurityData(std::shared_ptr<bmcweb::AsyncResp> aResp) 115 { 116 constexpr std::array<std::string_view, 1> interfaces = { 117 "xyz.openbmc_project.Chassis.Intrusion"}; 118 dbus::utility::getSubTree( 119 "/xyz/openbmc_project/Intrusion", 1, interfaces, 120 [aResp{std::move(aResp)}]( 121 const boost::system::error_code& ec, 122 const dbus::utility::MapperGetSubTreeResponse& subtree) { 123 if (ec) 124 { 125 // do not add err msg in redfish response, because this is not 126 // mandatory property 127 BMCWEB_LOG_INFO << "DBUS error: no matched iface " << ec << "\n"; 128 return; 129 } 130 // Iterate over all retrieved ObjectPaths. 131 for (const auto& object : subtree) 132 { 133 if (!object.second.empty()) 134 { 135 const auto service = object.second.front(); 136 getIntrusionByService(aResp, service.first, object.first); 137 return; 138 } 139 } 140 }); 141 } 142 143 inline void handleChassisCollectionGet( 144 App& app, const crow::Request& req, 145 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 146 { 147 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 148 { 149 return; 150 } 151 asyncResp->res.jsonValue["@odata.type"] = 152 "#ChassisCollection.ChassisCollection"; 153 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Chassis"; 154 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 155 156 constexpr std::array<std::string_view, 2> interfaces{ 157 "xyz.openbmc_project.Inventory.Item.Board", 158 "xyz.openbmc_project.Inventory.Item.Chassis"}; 159 collection_util::getCollectionMembers( 160 asyncResp, boost::urls::url("/redfish/v1/Chassis"), interfaces); 161 } 162 163 /** 164 * ChassisCollection derived class for delivering Chassis Collection Schema 165 * Functions triggers appropriate requests on DBus 166 */ 167 inline void requestRoutesChassisCollection(App& app) 168 { 169 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/") 170 .privileges(redfish::privileges::getChassisCollection) 171 .methods(boost::beast::http::verb::get)( 172 std::bind_front(handleChassisCollectionGet, std::ref(app))); 173 } 174 175 inline void 176 getChassisLocationCode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 177 const std::string& connectionName, 178 const std::string& path) 179 { 180 sdbusplus::asio::getProperty<std::string>( 181 *crow::connections::systemBus, connectionName, path, 182 "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 183 [asyncResp](const boost::system::error_code& ec, 184 const std::string& property) { 185 if (ec) 186 { 187 BMCWEB_LOG_ERROR << "DBUS response error for Location"; 188 messages::internalError(asyncResp->res); 189 return; 190 } 191 192 asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 193 property; 194 }); 195 } 196 197 inline void getChassisUUID(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 198 const std::string& connectionName, 199 const std::string& path) 200 { 201 sdbusplus::asio::getProperty<std::string>( 202 *crow::connections::systemBus, connectionName, path, 203 "xyz.openbmc_project.Common.UUID", "UUID", 204 [asyncResp](const boost::system::error_code& ec, 205 const std::string& chassisUUID) { 206 if (ec) 207 { 208 BMCWEB_LOG_ERROR << "DBUS response error for UUID"; 209 messages::internalError(asyncResp->res); 210 return; 211 } 212 asyncResp->res.jsonValue["UUID"] = chassisUUID; 213 }); 214 } 215 216 inline void 217 handleChassisGet(App& app, const crow::Request& req, 218 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 219 const std::string& chassisId) 220 { 221 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 222 { 223 return; 224 } 225 constexpr std::array<std::string_view, 2> interfaces = { 226 "xyz.openbmc_project.Inventory.Item.Board", 227 "xyz.openbmc_project.Inventory.Item.Chassis"}; 228 229 dbus::utility::getSubTree( 230 "/xyz/openbmc_project/inventory", 0, interfaces, 231 [asyncResp, chassisId(std::string(chassisId))]( 232 const boost::system::error_code& ec, 233 const dbus::utility::MapperGetSubTreeResponse& subtree) { 234 if (ec) 235 { 236 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 237 messages::internalError(asyncResp->res); 238 return; 239 } 240 // Iterate over all retrieved ObjectPaths. 241 for (const std::pair< 242 std::string, 243 std::vector<std::pair<std::string, std::vector<std::string>>>>& 244 object : subtree) 245 { 246 const std::string& path = object.first; 247 const std::vector<std::pair<std::string, std::vector<std::string>>>& 248 connectionNames = object.second; 249 250 sdbusplus::message::object_path objPath(path); 251 if (objPath.filename() != chassisId) 252 { 253 continue; 254 } 255 256 auto health = std::make_shared<HealthPopulate>(asyncResp); 257 258 if constexpr (bmcwebEnableHealthPopulate) 259 { 260 dbus::utility::getAssociationEndPoints( 261 path + "/all_sensors", 262 [health](const boost::system::error_code& ec2, 263 const dbus::utility::MapperEndPoints& resp) { 264 if (ec2) 265 { 266 return; // no sensors = no failures 267 } 268 health->inventory = resp; 269 }); 270 271 health->populate(); 272 } 273 274 if (connectionNames.empty()) 275 { 276 BMCWEB_LOG_ERROR << "Got 0 Connection names"; 277 continue; 278 } 279 280 asyncResp->res.jsonValue["@odata.type"] = 281 "#Chassis.v1_22_0.Chassis"; 282 asyncResp->res.jsonValue["@odata.id"] = 283 boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 284 asyncResp->res.jsonValue["Name"] = "Chassis Collection"; 285 asyncResp->res.jsonValue["ChassisType"] = "RackMount"; 286 asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"]["target"] = 287 boost::urls::format( 288 "/redfish/v1/Chassis/{}/Actions/Chassis.Reset", chassisId); 289 asyncResp->res 290 .jsonValue["Actions"]["#Chassis.Reset"]["@Redfish.ActionInfo"] = 291 boost::urls::format("/redfish/v1/Chassis/{}/ResetActionInfo", 292 chassisId); 293 asyncResp->res.jsonValue["PCIeDevices"]["@odata.id"] = 294 "/redfish/v1/Systems/system/PCIeDevices"; 295 296 dbus::utility::getAssociationEndPoints( 297 path + "/drive", 298 [asyncResp, 299 chassisId](const boost::system::error_code& ec3, 300 const dbus::utility::MapperEndPoints& resp) { 301 if (ec3 || resp.empty()) 302 { 303 return; // no drives = no failures 304 } 305 306 nlohmann::json reference; 307 reference["@odata.id"] = boost::urls::format( 308 "/redfish/v1/Chassis/{}/Drives", chassisId); 309 asyncResp->res.jsonValue["Drives"] = std::move(reference); 310 }); 311 312 const std::string& connectionName = connectionNames[0].first; 313 314 const std::vector<std::string>& interfaces2 = 315 connectionNames[0].second; 316 const std::array<const char*, 2> hasIndicatorLed = { 317 "xyz.openbmc_project.Inventory.Item.Panel", 318 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 319 320 const std::string assetTagInterface = 321 "xyz.openbmc_project.Inventory.Decorator.AssetTag"; 322 const std::string replaceableInterface = 323 "xyz.openbmc_project.Inventory.Decorator.Replaceable"; 324 for (const auto& interface : interfaces2) 325 { 326 if (interface == assetTagInterface) 327 { 328 sdbusplus::asio::getProperty<std::string>( 329 *crow::connections::systemBus, connectionName, path, 330 assetTagInterface, "AssetTag", 331 [asyncResp, 332 chassisId](const boost::system::error_code& ec2, 333 const std::string& property) { 334 if (ec2) 335 { 336 BMCWEB_LOG_ERROR 337 << "DBus response error for AssetTag: " << ec2; 338 messages::internalError(asyncResp->res); 339 return; 340 } 341 asyncResp->res.jsonValue["AssetTag"] = property; 342 }); 343 } 344 else if (interface == replaceableInterface) 345 { 346 sdbusplus::asio::getProperty<bool>( 347 *crow::connections::systemBus, connectionName, path, 348 replaceableInterface, "HotPluggable", 349 [asyncResp, 350 chassisId](const boost::system::error_code& ec2, 351 const bool property) { 352 if (ec2) 353 { 354 BMCWEB_LOG_ERROR 355 << "DBus response error for HotPluggable: " 356 << ec2; 357 messages::internalError(asyncResp->res); 358 return; 359 } 360 asyncResp->res.jsonValue["HotPluggable"] = property; 361 }); 362 } 363 } 364 365 for (const char* interface : hasIndicatorLed) 366 { 367 if (std::find(interfaces2.begin(), interfaces2.end(), 368 interface) != interfaces2.end()) 369 { 370 getIndicatorLedState(asyncResp); 371 getLocationIndicatorActive(asyncResp); 372 break; 373 } 374 } 375 376 sdbusplus::asio::getAllProperties( 377 *crow::connections::systemBus, connectionName, path, 378 "xyz.openbmc_project.Inventory.Decorator.Asset", 379 [asyncResp, chassisId(std::string(chassisId))]( 380 const boost::system::error_code& /*ec2*/, 381 const dbus::utility::DBusPropertiesMap& propertiesList) { 382 const std::string* partNumber = nullptr; 383 const std::string* serialNumber = nullptr; 384 const std::string* manufacturer = nullptr; 385 const std::string* model = nullptr; 386 const std::string* sparePartNumber = nullptr; 387 388 const bool success = sdbusplus::unpackPropertiesNoThrow( 389 dbus_utils::UnpackErrorPrinter(), propertiesList, 390 "PartNumber", partNumber, "SerialNumber", serialNumber, 391 "Manufacturer", manufacturer, "Model", model, 392 "SparePartNumber", sparePartNumber); 393 394 if (!success) 395 { 396 messages::internalError(asyncResp->res); 397 return; 398 } 399 400 if (partNumber != nullptr) 401 { 402 asyncResp->res.jsonValue["PartNumber"] = *partNumber; 403 } 404 405 if (serialNumber != nullptr) 406 { 407 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 408 } 409 410 if (manufacturer != nullptr) 411 { 412 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 413 } 414 415 if (model != nullptr) 416 { 417 asyncResp->res.jsonValue["Model"] = *model; 418 } 419 420 // SparePartNumber is optional on D-Bus 421 // so skip if it is empty 422 if (sparePartNumber != nullptr && !sparePartNumber->empty()) 423 { 424 asyncResp->res.jsonValue["SparePartNumber"] = 425 *sparePartNumber; 426 } 427 428 asyncResp->res.jsonValue["Name"] = chassisId; 429 asyncResp->res.jsonValue["Id"] = chassisId; 430 #ifdef BMCWEB_ALLOW_DEPRECATED_POWER_THERMAL 431 asyncResp->res.jsonValue["Thermal"]["@odata.id"] = 432 boost::urls::format("/redfish/v1/Chassis/{}/Thermal", 433 chassisId); 434 // Power object 435 asyncResp->res.jsonValue["Power"]["@odata.id"] = 436 boost::urls::format("/redfish/v1/Chassis/{}/Power", 437 chassisId); 438 #endif 439 #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM 440 asyncResp->res.jsonValue["ThermalSubsystem"]["@odata.id"] = 441 boost::urls::format( 442 "/redfish/v1/Chassis/{}/ThermalSubsystem", chassisId); 443 asyncResp->res.jsonValue["PowerSubsystem"]["@odata.id"] = 444 boost::urls::format("/redfish/v1/Chassis/{}/PowerSubsystem", 445 chassisId); 446 asyncResp->res.jsonValue["EnvironmentMetrics"]["@odata.id"] = 447 boost::urls::format( 448 "/redfish/v1/Chassis/{}/EnvironmentMetrics", chassisId); 449 #endif 450 // SensorCollection 451 asyncResp->res.jsonValue["Sensors"]["@odata.id"] = 452 boost::urls::format("/redfish/v1/Chassis/{}/Sensors", 453 chassisId); 454 asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 455 456 nlohmann::json::array_t computerSystems; 457 nlohmann::json::object_t system; 458 system["@odata.id"] = "/redfish/v1/Systems/system"; 459 computerSystems.emplace_back(std::move(system)); 460 asyncResp->res.jsonValue["Links"]["ComputerSystems"] = 461 std::move(computerSystems); 462 463 nlohmann::json::array_t managedBy; 464 nlohmann::json::object_t manager; 465 manager["@odata.id"] = "/redfish/v1/Managers/bmc"; 466 managedBy.emplace_back(std::move(manager)); 467 asyncResp->res.jsonValue["Links"]["ManagedBy"] = 468 std::move(managedBy); 469 getChassisState(asyncResp); 470 }); 471 472 for (const auto& interface : interfaces2) 473 { 474 if (interface == "xyz.openbmc_project.Common.UUID") 475 { 476 getChassisUUID(asyncResp, connectionName, path); 477 } 478 else if (interface == 479 "xyz.openbmc_project.Inventory.Decorator.LocationCode") 480 { 481 getChassisLocationCode(asyncResp, connectionName, path); 482 } 483 } 484 485 return; 486 } 487 488 // Couldn't find an object with that name. return an error 489 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 490 }); 491 492 getPhysicalSecurityData(asyncResp); 493 } 494 495 inline void 496 handleChassisPatch(App& app, const crow::Request& req, 497 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 498 const std::string& param) 499 { 500 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 501 { 502 return; 503 } 504 std::optional<bool> locationIndicatorActive; 505 std::optional<std::string> indicatorLed; 506 507 if (param.empty()) 508 { 509 return; 510 } 511 512 if (!json_util::readJsonPatch( 513 req, asyncResp->res, "LocationIndicatorActive", 514 locationIndicatorActive, "IndicatorLED", indicatorLed)) 515 { 516 return; 517 } 518 519 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 520 if (!locationIndicatorActive && !indicatorLed) 521 { 522 return; // delete this when we support more patch properties 523 } 524 if (indicatorLed) 525 { 526 asyncResp->res.addHeader( 527 boost::beast::http::field::warning, 528 "299 - \"IndicatorLED is deprecated. Use LocationIndicatorActive instead.\""); 529 } 530 531 constexpr std::array<std::string_view, 2> interfaces = { 532 "xyz.openbmc_project.Inventory.Item.Board", 533 "xyz.openbmc_project.Inventory.Item.Chassis"}; 534 535 const std::string& chassisId = param; 536 537 dbus::utility::getSubTree( 538 "/xyz/openbmc_project/inventory", 0, interfaces, 539 [asyncResp, chassisId, locationIndicatorActive, 540 indicatorLed](const boost::system::error_code& ec, 541 const dbus::utility::MapperGetSubTreeResponse& subtree) { 542 if (ec) 543 { 544 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 545 messages::internalError(asyncResp->res); 546 return; 547 } 548 549 // Iterate over all retrieved ObjectPaths. 550 for (const std::pair< 551 std::string, 552 std::vector<std::pair<std::string, std::vector<std::string>>>>& 553 object : subtree) 554 { 555 const std::string& path = object.first; 556 const std::vector<std::pair<std::string, std::vector<std::string>>>& 557 connectionNames = object.second; 558 559 sdbusplus::message::object_path objPath(path); 560 if (objPath.filename() != chassisId) 561 { 562 continue; 563 } 564 565 if (connectionNames.empty()) 566 { 567 BMCWEB_LOG_ERROR << "Got 0 Connection names"; 568 continue; 569 } 570 571 const std::vector<std::string>& interfaces3 = 572 connectionNames[0].second; 573 574 const std::array<const char*, 2> hasIndicatorLed = { 575 "xyz.openbmc_project.Inventory.Item.Panel", 576 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"}; 577 bool indicatorChassis = false; 578 for (const char* interface : hasIndicatorLed) 579 { 580 if (std::find(interfaces3.begin(), interfaces3.end(), 581 interface) != interfaces3.end()) 582 { 583 indicatorChassis = true; 584 break; 585 } 586 } 587 if (locationIndicatorActive) 588 { 589 if (indicatorChassis) 590 { 591 setLocationIndicatorActive(asyncResp, 592 *locationIndicatorActive); 593 } 594 else 595 { 596 messages::propertyUnknown(asyncResp->res, 597 "LocationIndicatorActive"); 598 } 599 } 600 if (indicatorLed) 601 { 602 if (indicatorChassis) 603 { 604 setIndicatorLedState(asyncResp, *indicatorLed); 605 } 606 else 607 { 608 messages::propertyUnknown(asyncResp->res, "IndicatorLED"); 609 } 610 } 611 return; 612 } 613 614 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 615 }); 616 } 617 618 /** 619 * Chassis override class for delivering Chassis Schema 620 * Functions triggers appropriate requests on DBus 621 */ 622 inline void requestRoutesChassis(App& app) 623 { 624 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 625 .privileges(redfish::privileges::getChassis) 626 .methods(boost::beast::http::verb::get)( 627 std::bind_front(handleChassisGet, std::ref(app))); 628 629 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/") 630 .privileges(redfish::privileges::patchChassis) 631 .methods(boost::beast::http::verb::patch)( 632 std::bind_front(handleChassisPatch, std::ref(app))); 633 } 634 635 inline void 636 doChassisPowerCycle(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 637 { 638 constexpr std::array<std::string_view, 1> interfaces = { 639 "xyz.openbmc_project.State.Chassis"}; 640 641 // Use mapper to get subtree paths. 642 dbus::utility::getSubTreePaths( 643 "/", 0, interfaces, 644 [asyncResp]( 645 const boost::system::error_code& ec, 646 const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { 647 if (ec) 648 { 649 BMCWEB_LOG_ERROR << "[mapper] Bad D-Bus request error: " << ec; 650 messages::internalError(asyncResp->res); 651 return; 652 } 653 654 const char* processName = "xyz.openbmc_project.State.Chassis"; 655 const char* interfaceName = "xyz.openbmc_project.State.Chassis"; 656 const char* destProperty = "RequestedPowerTransition"; 657 const std::string propertyValue = 658 "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 659 std::string objectPath = "/xyz/openbmc_project/state/chassis_system0"; 660 661 /* Look for system reset chassis path */ 662 if ((std::find(chassisList.begin(), chassisList.end(), objectPath)) == 663 chassisList.end()) 664 { 665 /* We prefer to reset the full chassis_system, but if it doesn't 666 * exist on some platforms, fall back to a host-only power reset 667 */ 668 objectPath = "/xyz/openbmc_project/state/chassis0"; 669 } 670 671 crow::connections::systemBus->async_method_call( 672 [asyncResp](const boost::system::error_code& ec2) { 673 // Use "Set" method to set the property value. 674 if (ec2) 675 { 676 BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec2; 677 messages::internalError(asyncResp->res); 678 return; 679 } 680 681 messages::success(asyncResp->res); 682 }, 683 processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 684 interfaceName, destProperty, 685 dbus::utility::DbusVariantType{propertyValue}); 686 }); 687 } 688 689 inline void handleChassisResetActionInfoPost( 690 App& app, const crow::Request& req, 691 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 692 const std::string& /*chassisId*/) 693 { 694 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 695 { 696 return; 697 } 698 BMCWEB_LOG_DEBUG << "Post Chassis Reset."; 699 700 std::string resetType; 701 702 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 703 { 704 return; 705 } 706 707 if (resetType != "PowerCycle") 708 { 709 BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 710 << resetType; 711 messages::actionParameterNotSupported(asyncResp->res, resetType, 712 "ResetType"); 713 714 return; 715 } 716 doChassisPowerCycle(asyncResp); 717 } 718 719 /** 720 * ChassisResetAction class supports the POST method for the Reset 721 * action. 722 * Function handles POST method request. 723 * Analyzes POST body before sending Reset request data to D-Bus. 724 */ 725 726 inline void requestRoutesChassisResetAction(App& app) 727 { 728 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/") 729 .privileges(redfish::privileges::postChassis) 730 .methods(boost::beast::http::verb::post)( 731 std::bind_front(handleChassisResetActionInfoPost, std::ref(app))); 732 } 733 734 inline void handleChassisResetActionInfoGet( 735 App& app, const crow::Request& req, 736 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 737 const std::string& chassisId) 738 { 739 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 740 { 741 return; 742 } 743 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 744 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 745 "/redfish/v1/Chassis/{}/ResetActionInfo", chassisId); 746 asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 747 748 asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 749 nlohmann::json::array_t parameters; 750 nlohmann::json::object_t parameter; 751 parameter["Name"] = "ResetType"; 752 parameter["Required"] = true; 753 parameter["DataType"] = "String"; 754 nlohmann::json::array_t allowed; 755 allowed.emplace_back("PowerCycle"); 756 parameter["AllowableValues"] = std::move(allowed); 757 parameters.emplace_back(std::move(parameter)); 758 759 asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 760 } 761 762 /** 763 * ChassisResetActionInfo derived class for delivering Chassis 764 * ResetType AllowableValues using ResetInfo schema. 765 */ 766 inline void requestRoutesChassisResetActionInfo(App& app) 767 { 768 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/ResetActionInfo/") 769 .privileges(redfish::privileges::getActionInfo) 770 .methods(boost::beast::http::verb::get)( 771 std::bind_front(handleChassisResetActionInfoGet, std::ref(app))); 772 } 773 774 } // namespace redfish 775