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