entity-manager: Handle left-over template vars
With current implementations for template variable replacement, if a
variable does not exist on D-Bus, it will be left as is and will appear
in the final configuration. However, if the string is intended to be
replaced and not handled properly after a replacement failure, the
variable itself will possibly be shown to users via Redfish/IPMI if the
consuming properties are used by those.
After performing the template variable replacement, a post-processing
step is added to check for any leftover template variables. These
leftovers may occur if the probed property is not available on D-Bus.
Any such variables are replaced with an empty string to avoid
unresolved placeholders.
The boundary of a template var is decided to be from the character "$"
to before a " " character, or the end of the keyPair's value string.
This conforms to the implicit rules currently applied to template
variable configuration that a template variable should not be
immediately followed by an arbitrary string without a space separating
them. This pattern can also be found in how the math configurations are
extracted, which looks for a math operator at the position that is one
character away from the end of the template variable [1].
The unit tests are also updated to test the new function that handles
left-over template variables.
[1]: https://github.com/openbmc/entity-manager/blob/3911d80afb6956b17c4f4b9a76c7eb45bb76e3b9/src/entity_manager/utils.cpp#L134
Tested: Unit tests pass
Tested with real configuration:
`$PRODUCT_PRODUCT_KK_NAME`, `$PRODUCT_KK_VERSION` and
`$PRODUCT_SERIAL_KK_NUMBER` are non-existent probed property on D-Bus.
```
{
"Exposes": [
...
],
"Name": "Mt.Mitchell_Motherboard",
"Probe": [
"xyz.openbmc_project.FruDevice({'BOARD_PRODUCT_NAME': 'MB'})",
"AND",
"FOUND('Mt.Mitchell_DCSCM_BMC')"
],
"Type": "Board",
"xyz.openbmc_project.Common.UUID": {
"UUID": "$MULTIRECORD_UUID"
},
"xyz.openbmc_project.Inventory.Decorator.Asset": {
"BuildDate": "$BOARD_MANUFACTURE_DATE",
"Manufacturer": "$PRODUCT_MANUFACTURER",
"Model": "$PRODUCT_PRODUCT_KK_NAME $PRODUCT_KK_VERSION",
"PartNumber": "$PRODUCT_PART_NUMBER",
"SerialNumber": "$PRODUCT_SERIAL_KK_NUMBER"
}
}
```
D-Bus results after the configuration is processed:
- `Model` has a space character which is the space between
`$PRODUCT_PRODUCT_KK_NAME` and `$PRODUCT_KK_VERSION` in the
configuration.
- SerialNumber is empty.
```
$ busctl introspect xyz.openbmc_project.EntityManager \
/xyz/openbmc_project/inventory/system/board/Mt_Mitchell_Motherboard
xyz.openbmc_project.Common.UUID interface - -
.UUID property s "xx-xx"
xyz.openbmc_project.Inventory.Decorator.Asset interface - -
.BuildDate property s "20221018Z"
.Manufacturer property s "NULL"
.Model property s " "
.PartNumber property s "ProductPN"
.SerialNumber property s ""
Change-Id: I4499baf3ebe9560e13932a49e324d1c8b0255623
Signed-off-by: Chau Ly <chaul@amperecomputing.com>
diff --git a/test/entity_manager/test_entity-manager.cpp b/test/entity_manager/test_entity-manager.cpp
index 7966090..cc59e44 100644
--- a/test/entity_manager/test_entity-manager.cpp
+++ b/test/entity_manager/test_entity-manager.cpp
@@ -240,6 +240,34 @@
EXPECT_EQ(expected, j["foo"]);
}
+TEST(TemplateCharReplace, leftOverTemplateVars)
+{
+ nlohmann::json j = {{"foo", "$EXISTENT_VAR and $NON_EXISTENT_VAR"}};
+ auto it = j.begin();
+
+ DBusInterface data;
+ data["EXISTENT_VAR"] = std::string("Replaced");
+
+ DBusObject object;
+ object["PATH"] = data;
+
+ em_utils::templateCharReplace(it, object, 0);
+
+ nlohmann::json expected = "Replaced and ";
+ EXPECT_EQ(expected, j["foo"]);
+}
+
+TEST(HandleLeftOverTemplateVars, replaceLeftOverTemplateVar)
+{
+ nlohmann::json j = {{"foo", "the Test $TEST is $TESTED"}};
+ auto it = j.begin();
+
+ em_utils::handleLeftOverTemplateVars(it);
+
+ nlohmann::json expected = "the Test is ";
+ EXPECT_EQ(expected, j["foo"]);
+}
+
TEST(MatchProbe, stringEqString)
{
nlohmann::json j = R"("foo")"_json;