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