associations: Add conditions support
Allow there to be multiple associations files that are selected based on
an inventory property condition specified inside of them. The file(s)
needs to be located in the same directory as the default associations
file, but can have any name as long as it ends in .json. If a
conditional associations file is found, the default associations file is
ignored.
For example:
{
"condition":
{
"path": "system/chassis/motherboard",
"interface": "xyz.openbmc_project.Inventory.Decorator.Asset",
"property": "Model",
"values": [
"ModelA",
"ModelB"
]
},
"associations":
[
// The same associations syntax as described above.
]
}
This states that the associations in this file are valid if the
motherboard inventory item has a Model property with a value of either
ModelA or ModelB.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ib0f32815dee718ea268715896b5470ed2f25119e
diff --git a/manager.cpp b/manager.cpp
index a64030a..0fae387 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -250,11 +250,23 @@
updateInterfaces(absPath, objit->second, refit, newObj,
restoreFromCache);
#ifdef CREATE_ASSOCIATIONS
- if (newObj)
+ if (!_associations.pendingCondition() && newObj)
{
_associations.createAssociations(absPath,
_status != ManagerStatus::RUNNING);
}
+ else if (!restoreFromCache &&
+ _associations.conditionMatch(objit->first, objit->second))
+ {
+ // The objit path/interface/property matched a pending condition.
+ // Now the associations are valid so attempt to create them against
+ // all existing objects. If this was the restoreFromCache path,
+ // objit doesn't contain property values so don't bother checking.
+ std::for_each(_refs.begin(), _refs.end(), [this](const auto& ref) {
+ _associations.createAssociations(
+ ref.first, _status != ManagerStatus::RUNNING);
+ });
+ }
#endif
++objit;
}
@@ -365,6 +377,55 @@
{
auto restoreFromCache = true;
updateObjects(objects, restoreFromCache);
+
+#ifdef CREATE_ASSOCIATIONS
+ // There may be conditional associations waiting to be loaded
+ // based on certain path/interface/property values. Now that
+ // _refs contains all objects with their property values, check
+ // which property values the conditions need and set them in the
+ // condition structure entries, using the actualValue field. Then
+ // the associations manager can check if the conditions are met.
+ if (_associations.pendingCondition())
+ {
+ ObjectReferences::iterator refIt;
+ InterfaceComposite::iterator ifaceIt;
+
+ auto& conditions = _associations.getConditions();
+ for (auto& condition : conditions)
+ {
+ refIt = _refs.find(_root + condition.path);
+ if (refIt != _refs.end())
+ {
+ ifaceIt = refIt->second.find(condition.interface);
+ }
+
+ if ((refIt != _refs.end()) && (ifaceIt != refIt->second.end()))
+ {
+ const auto& maker = _makers.find(condition.interface);
+ if (maker != _makers.end())
+ {
+ auto& getProperty =
+ std::get<GetPropertyValueType>(maker->second);
+
+ condition.actualValue =
+ getProperty(condition.property, ifaceIt->second);
+ }
+ }
+ }
+
+ // Check if a property value in a condition matches an
+ // actual property value just saved. If one did, now the
+ // associations file is valid so create its associations.
+ if (_associations.conditionMatch())
+ {
+ std::for_each(
+ _refs.begin(), _refs.end(), [this](const auto& ref) {
+ _associations.createAssociations(
+ ref.first, _status != ManagerStatus::RUNNING);
+ });
+ }
+ }
+#endif
}
}