Redfish: Add chassis reset

Add chassis reset by using Redfish.

Tested:
  Passed validator. Chassis reset worked.

Usage:
    POST on /redfish/v1/Chassis/chassis/Actions/Chassis.Reset/
      {
        "ResetType": "PowerCycle"
      }

Change-Id: Ia8949e6695e60ee63776ac70e4f8cd85a4b186c3
Signed-off-by: P.K. Lee <p.k.lee@quantatw.com>
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 19cd0b8..bdff035 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -79,6 +79,7 @@
         nodes.emplace_back(std::make_unique<Power>(app));
         nodes.emplace_back(std::make_unique<ChassisCollection>(app));
         nodes.emplace_back(std::make_unique<Chassis>(app));
+        nodes.emplace_back(std::make_unique<ChassisResetAction>(app));
         nodes.emplace_back(std::make_unique<UpdateService>(app));
         nodes.emplace_back(std::make_unique<StorageCollection>(app));
         nodes.emplace_back(std::make_unique<Storage>(app));
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index 2b098a9..d1119cd 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -323,6 +323,10 @@
                         "/redfish/v1/Chassis/" + chassisId;
                     asyncResp->res.jsonValue["Name"] = "Chassis Collection";
                     asyncResp->res.jsonValue["ChassisType"] = "RackMount";
+                    asyncResp->res.jsonValue["Actions"]["#Chassis.Reset"] = {
+                        {"target", "/redfish/v1/Chassis/" + chassisId +
+                                       "/Actions/Chassis.Reset"},
+                        {"ResetType@Redfish.AllowableValues", {"PowerCycle"}}};
                     asyncResp->res.jsonValue["PCIeDevices"] = {
                         {"@odata.id",
                          "/redfish/v1/Systems/system/PCIeDevices"}};
@@ -517,4 +521,75 @@
             "/xyz/openbmc_project/inventory", 0, interfaces);
     }
 };
+
+void doChassisPowerCycle(std::shared_ptr<AsyncResp> asyncResp)
+{
+    const char* processName = "xyz.openbmc_project.State.Chassis";
+    const char* objectPath = "/xyz/openbmc_project/state/chassis0";
+    const char* interfaceName = "xyz.openbmc_project.State.Chassis";
+    const char* destProperty = "RequestedPowerTransition";
+    const std::string propertyValue =
+        "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
+
+    crow::connections::systemBus->async_method_call(
+        [asyncResp](const boost::system::error_code ec) {
+            // Use "Set" method to set the property value.
+            if (ec)
+            {
+                BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec;
+                messages::internalError(asyncResp->res);
+                return;
+            }
+
+            messages::success(asyncResp->res);
+        },
+        processName, objectPath, "org.freedesktop.DBus.Properties", "Set",
+        interfaceName, destProperty, std::variant<std::string>{propertyValue});
+}
+
+/**
+ * ChassisResetAction class supports the POST method for the Reset
+ * action.
+ */
+class ChassisResetAction : public Node
+{
+  public:
+    ChassisResetAction(CrowApp& app) :
+        Node(app, "/redfish/v1/Chassis/<str>/Actions/Chassis.Reset/",
+             std::string())
+    {
+        entityPrivileges = {
+            {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+    }
+
+  private:
+    /**
+     * Function handles POST method request.
+     * Analyzes POST body before sending Reset request data to D-Bus.
+     */
+    void doPost(crow::Response& res, const crow::Request& req,
+                const std::vector<std::string>& params) override
+    {
+        BMCWEB_LOG_DEBUG << "Post Chassis Reset.";
+
+        std::string resetType;
+        auto asyncResp = std::make_shared<AsyncResp>(res);
+
+        if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType))
+        {
+            return;
+        }
+
+        if (resetType != "PowerCycle")
+        {
+            BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: "
+                             << resetType;
+            messages::actionParameterNotSupported(asyncResp->res, resetType,
+                                                  "ResetType");
+
+            return;
+        }
+        doChassisPowerCycle(asyncResp);
+    }
+};
 } // namespace redfish