Sync common interface property if keyword updated
This commit implements changes for updating common interface property(if
any) for a given FRU. When a keyword value is updated either
from vpd-tool or from vpd-manager WriteKeyword API, the corresponding
common interface property should also be updated on PIM for the FRU as
well as for all inherited FRUs.
Test:
```
Tested on rainier 2s2u simics setup
1. Ensure BMC is in Ready state
2. Read VINI PN of /system/chassis/motherboard using vpd-tool
3. Read Decorator.Asset PartNumber property of /system/chassis/
motherboard using busctl
4. Change VINI PN of /system/chassis/motherboard using vpd-tool
5. Read VINI PN of /system/chassis/motherboard using vpd-tool and
observe that the PN value is updated. Also check the same for
inherited FRUs /system/chassis and
/system/chassis/motherboard/tod_battery
6. Read Decorator.Asset PartNumber property of
/system/chassis/motherboard and its inherited FRUs using busctl and
observe the property got updated with the expected value.
7. Read Decorator.Asset PartNumber property of some non-inherited FRUs
like /system and observe their PartNumber did not get updated.
```
Change-Id: I51955b842640f66a129453bda6cb28ffd478eea4
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/vpd-manager/include/utility/vpd_specific_utility.hpp b/vpd-manager/include/utility/vpd_specific_utility.hpp
index 0228e74..2e360e7 100644
--- a/vpd-manager/include/utility/vpd_specific_utility.hpp
+++ b/vpd-manager/include/utility/vpd_specific_utility.hpp
@@ -887,5 +887,170 @@
i_fruPath + "]. Error: " + std::string(l_ex.what()));
}
}
+
+/**
+ * @brief API to get common interface(s) properties corresponding to given
+ * record and keyword.
+ *
+ * For a given record and keyword, this API finds the corresponding common
+ * interfaces(s) properties from the system config JSON and populates an
+ * interface map with the respective properties and values.
+ *
+ * @param[in] i_paramsToWriteData - Input details.
+ * @param[in] i_commonInterfaceJson - Common interface JSON object.
+ *
+ * @return Returns a map of common interface(s) and properties corresponding to
+ * the record and keyword. An empty map is returned if no such common
+ * interface(s) and properties are found.
+ */
+inline types::InterfaceMap getCommonInterfaceProperties(
+ const types::WriteVpdParams& i_paramsToWriteData,
+ const nlohmann::json& i_commonInterfaceJson) noexcept
+{
+ types::InterfaceMap l_interfaceMap;
+ try
+ {
+ const types::IpzData* l_ipzData =
+ std::get_if<types::IpzData>(&i_paramsToWriteData);
+
+ if (!l_ipzData)
+ {
+ throw std::runtime_error("Invalid VPD type");
+ }
+
+ auto l_populateInterfaceMap = [&l_ipzData = std::as_const(l_ipzData),
+ &l_interfaceMap](
+ const auto& l_interfacesPropPair) {
+ // find matching property value pair
+ const auto l_matchPropValuePairIt = std::find_if(
+ l_interfacesPropPair.value().items().begin(),
+ l_interfacesPropPair.value().items().end(),
+ [&l_ipzData](const auto& l_propValuePair) {
+ return (l_propValuePair.value().value("recordName", "") ==
+ std::get<0>(*l_ipzData) &&
+ l_propValuePair.value().value("keywordName", "") ==
+ std::get<1>(*l_ipzData));
+ });
+
+ if (l_matchPropValuePairIt !=
+ l_interfacesPropPair.value().items().end())
+ {
+ // add property map to interface map
+ l_interfaceMap.emplace(
+ l_interfacesPropPair.key(),
+ types::PropertyMap{
+ {l_matchPropValuePairIt.key(),
+ vpdSpecificUtility::encodeKeyword(
+ std::string(std::get<2>(*l_ipzData).begin(),
+ std::get<2>(*l_ipzData).end()),
+ l_matchPropValuePairIt.value().value("encoding",
+ ""))}});
+ }
+ };
+
+ // iterate through all common interfaces and populate interface map
+ std::for_each(i_commonInterfaceJson.items().begin(),
+ i_commonInterfaceJson.items().end(),
+ l_populateInterfaceMap);
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage(
+ "Failed to find common interface properties. Error: " +
+ std::string(l_ex.what()));
+ }
+ return l_interfaceMap;
+}
+
+/**
+ * @brief API to update common interface(s) properties when keyword is updated.
+ *
+ * For a given keyword update on a EEPROM path, this API syncs the keyword
+ * update to respective common interface(s) properties of the base FRU and all
+ * inherited FRUs.
+ *
+ * @param[in] i_fruPath - EEPROM path of FRU.
+ * @param[in] i_paramsToWriteData - Input details.
+ * @param[in] i_sysCfgJsonObj - System config JSON.
+ *
+ */
+inline void updateCiPropertyOfInheritedFrus(
+ const std::string& i_fruPath,
+ const types::WriteVpdParams& i_paramsToWriteData,
+ const nlohmann::json& i_sysCfgJsonObj) noexcept
+{
+ try
+ {
+ if (!i_sysCfgJsonObj.contains("commonInterfaces"))
+ {
+ // no common interfaces in JSON, nothing to do
+ return;
+ }
+
+ if (!i_sysCfgJsonObj.contains("frus"))
+ {
+ throw std::runtime_error("Mandatory tag(s) missing from JSON");
+ }
+
+ if (!i_sysCfgJsonObj["frus"].contains(i_fruPath))
+ {
+ throw std::runtime_error(
+ "VPD path [" + i_fruPath + "] not found in system config JSON");
+ }
+
+ if (!std::get_if<types::IpzData>(&i_paramsToWriteData))
+ {
+ throw std::runtime_error("Unsupported VPD type");
+ }
+
+ // iterate through all inventory paths for given EEPROM path,
+ // if for an inventory path, "inherit" tag is true,
+ // update the inventory path's com.ibm.ipzvpd.<record>,keyword
+ // property
+
+ types::ObjectMap l_objectInterfaceMap;
+
+ const types::InterfaceMap l_interfaceMap = getCommonInterfaceProperties(
+ i_paramsToWriteData, i_sysCfgJsonObj["commonInterfaces"]);
+
+ if (l_interfaceMap.empty())
+ {
+ // nothing to do
+ return;
+ }
+
+ auto l_populateObjectInterfaceMap =
+ [&l_objectInterfaceMap, &l_interfaceMap = std::as_const(
+ l_interfaceMap)](const auto& l_Fru) {
+ if (l_Fru.value("inherit", true) &&
+ l_Fru.contains("inventoryPath"))
+ {
+ l_objectInterfaceMap.emplace(
+ sdbusplus::message::object_path{l_Fru["inventoryPath"]},
+ l_interfaceMap);
+ }
+ };
+
+ std::for_each(i_sysCfgJsonObj["frus"][i_fruPath].begin(),
+ i_sysCfgJsonObj["frus"][i_fruPath].end(),
+ l_populateObjectInterfaceMap);
+
+ if (!l_objectInterfaceMap.empty())
+ {
+ // notify PIM
+ if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
+ {
+ throw std::runtime_error(
+ "Call to PIM failed for VPD file " + i_fruPath);
+ }
+ }
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage(
+ "Failed to update common interface properties of FRU [" +
+ i_fruPath + "]. Error: " + std::string(l_ex.what()));
+ }
+}
} // namespace vpdSpecificUtility
} // namespace vpd