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