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