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