Add Storage Health & Update Systems Health

This adds health to storage based on drive inventory and
updates systems health to include drives.

This also fixes properties that are manditory in drives to
make this patch pass the validator.

Tested:

Validator Passed.

Failed a drive and saw:

{
    "@odata.context": "/redfish/v1/$metadata#Storage.Storage",
    "@odata.id": "/redfish/v1/Systems/system/Storage/1",
    "@odata.type": "#Storage.v1_7_1.Storage",
    "Drives": [
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_1"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_2"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_3"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_4"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_5"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_6"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_7"
        },
        {
            "@odata.id": "/redfish/v1/Systems/system/Storage/1/Drive/Drive_8"
        }
    ],
    "Drives@odata.count": 8,
    "Id": "1",
    "Name": "Storage Controller",
    "Status": {
        "Health": "Warning",
        "HealthRollup": "Warning",
        "State": "Enabled"
   }
}

And In systems:

    "Status": {
        "Health": "Warning",
        "HealthRollup": "Warning",
        "State": "Enabled"
    },

Change-Id: I7abf042ac51b1fbe9e4ee0b72876e9be96e60b7c
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/redfish-core/lib/storage.hpp b/redfish-core/lib/storage.hpp
index 611c7e7..9c51975 100644
--- a/redfish-core/lib/storage.hpp
+++ b/redfish-core/lib/storage.hpp
@@ -15,6 +15,8 @@
 */
 #pragma once
 
+#include "health.hpp"
+
 #include <node.hpp>
 
 namespace redfish
@@ -74,6 +76,7 @@
         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
         res.jsonValue["Name"] = "Storage Controller";
         res.jsonValue["Id"] = "1";
+        res.jsonValue["Status"]["State"] = "Enabled";
 
         auto asyncResp = std::make_shared<AsyncResp>(res);
         crow::connections::systemBus->async_method_call(
@@ -83,12 +86,18 @@
                     asyncResp->res.jsonValue["Drives"];
                 storageArray = nlohmann::json::array();
                 asyncResp->res.jsonValue["Drives@odata.count"] = 0;
+                auto health = std::make_shared<HealthPopulate>(asyncResp);
+
                 if (ec)
                 {
                     BMCWEB_LOG_ERROR << "Drive mapper call error";
                     messages::internalError(asyncResp->res);
                     return;
                 }
+
+                health->inventory = storageList;
+                health->populate();
+
                 for (const std::string &objpath : storageList)
                 {
                     std::size_t lastPos = objpath.rfind("/");
@@ -178,6 +187,8 @@
                     "/redfish/v1/$metadata#Drive.Drive";
                 asyncResp->res.jsonValue["@odata.id"] =
                     "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId;
+                asyncResp->res.jsonValue["Name"] = driveId;
+                asyncResp->res.jsonValue["Id"] = driveId;
 
                 if (connectionNames.size() != 1)
                 {
@@ -197,12 +208,11 @@
 
                 const std::string &connectionName = connectionNames[0].first;
                 crow::connections::systemBus->async_method_call(
-                    [asyncResp,
-                     driveId](const boost::system::error_code ec,
-                              const std::vector<std::pair<
-                                  std::string,
-                                  std::variant<bool, std::string, uint64_t>>>
-                                  &propertiesList) {
+                    [asyncResp](const boost::system::error_code ec,
+                                const std::vector<std::pair<
+                                    std::string,
+                                    std::variant<bool, std::string, uint64_t>>>
+                                    &propertiesList) {
                         if (ec)
                         {
                             // this interface isn't necessary
@@ -233,8 +243,6 @@
                                 asyncResp->res.jsonValue[propertyName] = *value;
                             }
                         }
-                        asyncResp->res.jsonValue["Name"] = driveId;
-                        asyncResp->res.jsonValue["Id"] = driveId;
                     },
                     connectionName, path, "org.freedesktop.DBus.Properties",
                     "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
@@ -242,35 +250,32 @@
                 // default it to Enabled
                 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
 
+                auto health = std::make_shared<HealthPopulate>(asyncResp);
+                health->inventory = std::vector<std::string>{path};
+
+                health->populate();
+
                 crow::connections::systemBus->async_method_call(
                     [asyncResp, path](const boost::system::error_code ec,
                                       const std::variant<bool> present) {
                         // this interface isn't necessary, only check it if we
                         // get a good return
-                        if (!ec)
+                        if (ec)
                         {
-                            const bool *enabled = std::get_if<bool>(&present);
-                            if (enabled == nullptr)
-                            {
-                                BMCWEB_LOG_DEBUG << "Illegal property present";
-                                messages::internalError(asyncResp->res);
-                                return;
-                            }
-                            if (!(*enabled))
-                            {
-                                asyncResp->res.jsonValue["Status"]["State"] =
-                                    "Disabled";
-                                return;
-                            }
+                            return;
                         }
-
-                        // only populate if Enabled, assume enabled unless item
-                        // interface says otherwise
-                        auto health =
-                            std::make_shared<HealthPopulate>(asyncResp);
-                        health->inventory = std::vector<std::string>{path};
-
-                        health->populate();
+                        const bool *enabled = std::get_if<bool>(&present);
+                        if (enabled == nullptr)
+                        {
+                            BMCWEB_LOG_DEBUG << "Illegal property present";
+                            messages::internalError(asyncResp->res);
+                            return;
+                        }
+                        if (!(*enabled))
+                        {
+                            asyncResp->res.jsonValue["Status"]["State"] =
+                                "Disabled";
+                        }
                     },
                     connectionName, path, "org.freedesktop.DBus.Properties",
                     "Get", "xyz.openbmc_project.Inventory.Item", "Present");
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index c51f37d..707eca9 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -1628,9 +1628,10 @@
         };
         auto asyncResp = std::make_shared<AsyncResp>(res);
 
-        constexpr const std::array<const char *, 2> inventoryForSystems = {
+        constexpr const std::array<const char *, 3> inventoryForSystems = {
             "xyz.openbmc_project.Inventory.Item.Dimm",
-            "xyz.openbmc_project.Inventory.Item.Cpu"};
+            "xyz.openbmc_project.Inventory.Item.Cpu",
+            "xyz.openbmc_project.Inventory.Item.Drive"};
 
         auto health = std::make_shared<HealthPopulate>(asyncResp);
         crow::connections::systemBus->async_method_call(