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