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