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