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