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