Set one-time properties and PrettyName

This commit adds support for the following:

* Sets "one-time" properties in the inventory. For a given object, if
  the property does not already exist, we set the property on D-Bus. The
  current use-case is to only set the Functional and Enabled properties.

* Sets the PrettyName property when priming the inventory. This makes
  sure we have the name set even when we haven't collected the said
  FRU's VPD. This is useful for FRUs where we don't collect VPD yet
  (DIMMs, for example). For this to work, the property needs to be
  available under the extraInterfaces key in the JSON entry for the
  FRU. For ex:

```
"extraInterfaces": {
    "xyz.openbmc_project.Inventory.Item": {
        "PrettyName": "Memory Controller Channel"
    }
```

Signed-off-by: Santosh Puranik <santosh.puranik@in.ibm.com>
Change-Id: Idd40836482a2f4dd512116c9e373da66df7bea1a
diff --git a/ibm_vpd_app.cpp b/ibm_vpd_app.cpp
index b7de1a6..c6e58e6 100644
--- a/ibm_vpd_app.cpp
+++ b/ibm_vpd_app.cpp
@@ -466,6 +466,60 @@
 }
 
 /**
+ * @brief Set certain one time properties in the inventory
+ * Use this function to insert the Functional and Enabled properties into the
+ * inventory map. This function first checks if the object in question already
+ * has these properties hosted on D-Bus, if the property is already there, it is
+ * not modified, hence the name "one time". If the property is not already
+ * present, it will be added to the map with a suitable default value (true for
+ * Functional and false for Enabled)
+ *
+ * @param[in] object - The inventory D-Bus obejct without the inventory prefix.
+ * @param[inout] interfaces - Reference to a map of inventory interfaces to
+ * which the properties will be attached.
+ */
+static void setOneTimeProperties(const std::string& object,
+                                 inventory::InterfaceMap& interfaces)
+{
+    auto bus = sdbusplus::bus::new_default();
+    auto objectPath = INVENTORY_PATH + object;
+    auto prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
+                                    objectPath.c_str(),
+                                    "org.freedesktop.DBus.Properties", "Get");
+    prop.append("xyz.openbmc_project.State.Decorator.OperationalStatus");
+    prop.append("Functional");
+    try
+    {
+        auto result = bus.call(prop);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        // Treat as property unavailable
+        inventory::PropertyMap prop;
+        prop.emplace("Functional", true);
+        interfaces.emplace(
+            "xyz.openbmc_project.State.Decorator.OperationalStatus",
+            move(prop));
+    }
+    prop = bus.new_method_call("xyz.openbmc_project.Inventory.Manager",
+                               objectPath.c_str(),
+                               "org.freedesktop.DBus.Properties", "Get");
+    prop.append("xyz.openbmc_project.Object.Enable");
+    prop.append("Enabled");
+    try
+    {
+        auto result = bus.call(prop);
+    }
+    catch (const sdbusplus::exception::SdBusError& e)
+    {
+        // Treat as property unavailable
+        inventory::PropertyMap prop;
+        prop.emplace("Enabled", false);
+        interfaces.emplace("xyz.openbmc_project.Object.Enable", move(prop));
+    }
+}
+
+/**
  * @brief Prime the Inventory
  * Prime the inventory by populating only the location code,
  * type interface and the inventory object for the frus
@@ -497,7 +551,8 @@
                 inventory::PropertyMap presProp;
                 presProp.emplace("Present", false);
                 interfaces.emplace("xyz.openbmc_project.Inventory.Item",
-                                   move(presProp));
+                                   presProp);
+                setOneTimeProperties(object, interfaces);
                 if (itemEEPROM.find("extraInterfaces") != itemEEPROM.end())
                 {
                     for (const auto& eI : itemEEPROM["extraInterfaces"].items())
@@ -526,6 +581,23 @@
                         {
                             interfaces.emplace(move(eI.key()), move(props));
                         }
+                        else if (eI.key() ==
+                                 "xyz.openbmc_project.Inventory.Item")
+                        {
+                            for (auto& val : eI.value().items())
+                            {
+                                if (val.key() == "PrettyName")
+                                {
+                                    presProp.emplace(val.key(),
+                                                     val.value().get<string>());
+                                }
+                            }
+                            // Use insert_or_assign here as we may already have
+                            // inserted the present property only earlier in
+                            // this function under this same interface.
+                            interfaces.insert_or_assign(eI.key(),
+                                                        move(presProp));
+                        }
                     }
                 }
                 objects.emplace(move(object), move(interfaces));
@@ -924,6 +996,14 @@
         const auto& objectPath = item["inventoryPath"];
         sdbusplus::message::object_path object(objectPath);
 
+        if (isSystemVpd)
+        {
+            // Populate one time properties for the system VPD and its sub-frus.
+            // For the remaining FRUs, this will get handled as a part of
+            // priming the inventory.
+            setOneTimeProperties(objectPath, interfaces);
+        }
+
         // Populate the VPD keywords and the common interfaces only if we
         // are asked to inherit that data from the VPD, else only add the
         // extraInterfaces.