Do tmpl substitutions using all properties on path
The current code would substitute the template arguments in the JSON
files, such as $bus, by only looking at the properties of the interface
that passed the probe.
This commit will try to find a substitution using the properties of all
of the interfaces on the same object path as the interface that passed
the probe. It does this by reading and storing the properties of all
interfaces that came back from the existing GetSubTree call that finds
the paths of the probed interfaces, instead of just limiting it to the
interfaces that were probed. The template substitutions are then tried
on the properties of all interfaces until one is successful.
This change is being made so that the interface used in the probe
doesn't also need to contain properties for the device details, such as
the bus property, that otherwise wouldn't belong there. For example,
the com.ibm.ipzvpd.VINI interface, which models EEPROM contents, is
currently used in probes on IBM systems, and with this change the bus
and address properties can now be on a separate interface, such as the
recently proposed xyz.openbmc_project.Inventory.Decorator.I2CDevice.
Tested: Tested that the $bus template can be successfully filled in
with the Bus property from an interface other than the one the probe was
matched on.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ic6f1539b38f6a4098f131d7f14cad6b6ddff041f
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index ccca133..932b6f9 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -108,7 +108,7 @@
void registerCallback(nlohmann::json& systemConfiguration,
sdbusplus::asio::object_server& objServer,
- const std::string& interfaces);
+ const std::string& path);
static std::shared_ptr<sdbusplus::asio::dbus_interface>
createInterface(sdbusplus::asio::object_server& objServer,
@@ -169,7 +169,7 @@
return;
}
- scan->dbusProbeObjects[std::get<2>(call)].emplace_back(resp);
+ scan->dbusProbeObjects[std::get<1>(call)][std::get<2>(call)] = resp;
},
std::get<0>(call), std::get<1>(call), "org.freedesktop.DBus.Properties",
"GetAll", std::get<2>(call));
@@ -180,17 +180,19 @@
}
}
-// calls the mapper to find all exposed objects of an interface type
-// and creates a vector<flat_map> that contains all the key value pairs
-// getManagedObjects
+// Populates scan->dbusProbeObjects with all interfaces and properties
+// for the paths that own the interfaces passed in.
void findDbusObjects(std::vector<std::shared_ptr<PerformProbe>>&& probeVector,
boost::container::flat_set<std::string>&& interfaces,
std::shared_ptr<PerformScan> scan, size_t retries = 5)
{
-
- for (const auto& [interface, _] : scan->dbusProbeObjects)
+ // Filter out interfaces already obtained.
+ for (const auto& [path, probeInterfaces] : scan->dbusProbeObjects)
{
- interfaces.erase(interface);
+ for (const auto& [interface, _] : probeInterfaces)
+ {
+ interfaces.erase(interface);
+ }
}
if (interfaces.empty())
{
@@ -240,14 +242,22 @@
{
for (const std::string& iface : ifaces)
{
- auto ifaceObjFind = interfaces.find(iface);
-
- if (ifaceObjFind != interfaces.end())
+ // The 3 default org.freedeskstop interfaces (Peer,
+ // Introspectable, and Properties) are returned by
+ // the mapper but don't have properties, so don't bother
+ // with the GetAll call to save some cycles.
+ if (!boost::algorithm::starts_with(iface,
+ "org.freedesktop"))
{
interfaceConnections.emplace(busname, path, iface);
}
}
}
+
+ // Get a PropertiesChanged callback for all
+ // interfaces on this path.
+ registerCallback(scan->_systemConfiguration, scan->objServer,
+ path);
}
if (interfaceConnections.empty())
@@ -272,42 +282,52 @@
}
// probes dbus interface dictionary for a key with a value that matches a regex
+// When an interface passes a probe, also save its D-Bus path with it.
bool probeDbus(const std::string& interface,
const std::map<std::string, nlohmann::json>& matches,
FoundDeviceT& devices, std::shared_ptr<PerformScan> scan,
bool& foundProbe)
{
- std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
- dbusObject = scan->dbusProbeObjects[interface];
- if (dbusObject.empty())
- {
- foundProbe = false;
- return false;
- }
- foundProbe = true;
-
bool foundMatch = false;
- for (auto& device : dbusObject)
+ foundProbe = false;
+
+ for (const auto& [path, interfaces] : scan->dbusProbeObjects)
{
- bool deviceMatches = true;
- for (auto& match : matches)
+ auto it = interfaces.find(interface);
+ if (it == interfaces.end())
{
- auto deviceValue = device.find(match.first);
- if (deviceValue != device.end())
+ continue;
+ }
+
+ foundProbe = true;
+
+ bool deviceMatches = true;
+ const boost::container::flat_map<std::string, BasicVariantType>&
+ properties = it->second;
+
+ for (const auto& [matchProp, matchJSON] : matches)
+ {
+ auto deviceValue = properties.find(matchProp);
+ if (deviceValue != properties.end())
{
- deviceMatches = matchProbe(match.second, deviceValue->second);
+ deviceMatches = matchProbe(matchJSON, deviceValue->second);
}
else
{
+ // Move on to the next DBus path
deviceMatches = false;
break;
}
}
if (deviceMatches)
{
- devices.emplace_back(device);
+ if constexpr (DEBUG)
+ {
+ std::cerr << "probeDBus: Found probe match on " << path << " "
+ << interface << "\n";
+ }
+ devices.emplace_back(properties, path);
foundMatch = true;
- deviceMatches = false; // for next iteration
}
}
return foundMatch;
@@ -315,11 +335,8 @@
// default probe entry point, iterates a list looking for specific types to
// call specific probe functions
-bool probe(
- const std::vector<std::string>& probeCommand,
- std::shared_ptr<PerformScan> scan,
- std::vector<boost::container::flat_map<std::string, BasicVariantType>>&
- foundDevs)
+bool probe(const std::vector<std::string>& probeCommand,
+ std::shared_ptr<PerformScan> scan, FoundDeviceT& foundDevs)
{
const static std::regex command(R"(\((.*)\))");
std::smatch match;
@@ -450,7 +467,8 @@
if (ret && foundDevs.size() == 0)
{
foundDevs.emplace_back(
- boost::container::flat_map<std::string, BasicVariantType>{});
+ boost::container::flat_map<std::string, BasicVariantType>{},
+ std::string{});
}
if (matchOne && ret)
{
@@ -463,9 +481,10 @@
return ret;
}
-PerformProbe::PerformProbe(const std::vector<std::string>& probeCommand,
- std::shared_ptr<PerformScan>& scanPtr,
- std::function<void(FoundDeviceT&)>&& callback) :
+PerformProbe::PerformProbe(
+ const std::vector<std::string>& probeCommand,
+ std::shared_ptr<PerformScan>& scanPtr,
+ std::function<void(FoundDeviceT&, const DBusProbeObjectT&)>&& callback) :
_probeCommand(probeCommand),
scan(scanPtr), _callback(std::move(callback))
{}
@@ -474,7 +493,7 @@
FoundDeviceT foundDevs;
if (probe(_probeCommand, scan, foundDevs))
{
- _callback(foundDevs);
+ _callback(foundDevs, scan->dbusProbeObjects);
}
}
@@ -1278,7 +1297,8 @@
auto thisRef = shared_from_this();
auto probePointer = std::make_shared<PerformProbe>(
probeCommand, thisRef,
- [&, recordPtr, probeName](FoundDeviceT& foundDevices) {
+ [&, recordPtr, probeName](FoundDeviceT& foundDevices,
+ const DBusProbeObjectT& allInterfaces) {
_passed = true;
std::set<nlohmann::json> usedNames;
@@ -1294,7 +1314,8 @@
for (auto itr = foundDevices.begin();
itr != foundDevices.end();)
{
- std::string recordName = getRecordName(*itr, probeName);
+ std::string recordName =
+ getRecordName(std::get<0>(*itr), probeName);
auto fromLastJson = lastJson.find(recordName);
if (fromLastJson != lastJson.end())
@@ -1349,8 +1370,24 @@
std::optional<std::string> replaceStr;
- for (auto& foundDevice : foundDevices)
+ for (auto& foundDeviceAndPath : foundDevices)
{
+ const boost::container::flat_map<
+ std::string, BasicVariantType>& foundDevice =
+ std::get<0>(foundDeviceAndPath);
+ const std::string& path = std::get<1>(foundDeviceAndPath);
+
+ // Need all interfaces on this path so that template
+ // substitutions can be done with any of the contained
+ // properties.
+ auto allInterfacesOnPath = allInterfaces.find(path);
+ if (allInterfacesOnPath == allInterfaces.end())
+ {
+ // Should be impossible at this point.
+ std::cerr << "Unrecognized path " << path << "\n";
+ continue;
+ }
+
nlohmann::json record = *recordPtr;
std::string recordName =
getRecordName(foundDevice, probeName);
@@ -1367,8 +1404,9 @@
nlohmann::json copyForName = {{"Name", getName.value()}};
nlohmann::json::iterator copyIt = copyForName.begin();
- std::optional<std::string> replaceVal = templateCharReplace(
- copyIt, foundDevice, foundDeviceIdx, replaceStr);
+ std::optional<std::string> replaceVal =
+ templateCharReplace(copyIt, allInterfacesOnPath->second,
+ foundDeviceIdx, replaceStr);
if (!replaceStr && replaceVal)
{
@@ -1377,7 +1415,8 @@
replaceStr = replaceVal;
copyForName = {{"Name", getName.value()}};
copyIt = copyForName.begin();
- templateCharReplace(copyIt, foundDevice,
+ templateCharReplace(copyIt,
+ allInterfacesOnPath->second,
foundDeviceIdx, replaceStr);
}
}
@@ -1400,7 +1439,8 @@
continue; // already covered above
}
- templateCharReplace(keyPair, foundDevice,
+ templateCharReplace(keyPair,
+ allInterfacesOnPath->second,
foundDeviceIdx, replaceStr);
}
@@ -1422,7 +1462,8 @@
keyPair != expose.end(); keyPair++)
{
- templateCharReplace(keyPair, foundDevice,
+ templateCharReplace(keyPair,
+ allInterfacesOnPath->second,
foundDeviceIdx, replaceStr);
bool isBind =
@@ -1562,11 +1603,6 @@
it++;
}
- for (const std::string& interface : dbusProbeInterfaces)
- {
- registerCallback(_systemConfiguration, objServer, interface);
- }
-
// probe vector stores a shared_ptr to each PerformProbe that cares
// about a dbus interface
findDbusObjects(std::move(dbusProbePointers),
@@ -1811,12 +1847,12 @@
void registerCallback(nlohmann::json& systemConfiguration,
sdbusplus::asio::object_server& objServer,
- const std::string& interface)
+ const std::string& path)
{
static boost::container::flat_map<std::string, sdbusplus::bus::match::match>
dbusMatches;
- auto find = dbusMatches.find(interface);
+ auto find = dbusMatches.find(path);
if (find != dbusMatches.end())
{
return;
@@ -1829,9 +1865,9 @@
sdbusplus::bus::match::match match(
static_cast<sdbusplus::bus::bus&>(*SYSTEM_BUS),
- "type='signal',member='PropertiesChanged',arg0='" + interface + "'",
+ "type='signal',member='PropertiesChanged',path='" + path + "'",
eventHandler);
- dbusMatches.emplace(interface, std::move(match));
+ dbusMatches.emplace(path, std::move(match));
}
int main()