summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--README.md23
-rw-r--r--events.cpp99
-rw-r--r--events.hpp132
-rw-r--r--example/events.d/match2.yaml32
-rw-r--r--test/test.cpp78
6 files changed, 365 insertions, 0 deletions
diff --git a/Makefile.am b/Makefile.am
index 36edbca..16d35b9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -14,6 +14,7 @@ noinst_LTLIBRARIES = libmanager.la
libmanager_la_SOURCES = \
xyz.openbmc_project.Inventory.Manager.cpp \
generated.cpp \
+ events.cpp \
manager.cpp
libmanager_la_LIBADD = libextra.la
diff --git a/README.md b/README.md
index 5f479fc..c7c64a1 100644
--- a/README.md
+++ b/README.md
@@ -47,15 +47,38 @@ The available filters provided by PIM are:
* propertyChangedTo - Only match events when the specified property has
the specified value.
+* propertyIs - Only match events when the specified property has
+the specified value.
----
**propertyChangedTo**
+The property under test is obtained from an sdbus message
+generated from an org.freedesktop.DBus.Properties.PropertiesChanged
+signal payload.
+
Supported arguments for the propertyChangedTo filter are:
* interface - The interface hosting the property to be checked.
* property - The property to check.
* value - The value to check.
+----
+**propertyIs**
+
+The property under test is obtained by invoking
+org.freedesktop.Properties.Get on the specified interface.
+
+Supported arguments for the propertyIs filter are:
+* path - The object hosting the property to be checked.
+* interface - The interface hosting the property to be checked.
+* property - The property to check.
+* value - The value to check.
+* service - An optional DBus service name.
+
+The service argument is optional. If provided that service will
+be called explicitly. If omitted, the service will be obtained
+with an xyz.openbmc_project.ObjectMapper lookup.
+
---
**actions**
diff --git a/events.cpp b/events.cpp
new file mode 100644
index 0000000..41a6e5f
--- /dev/null
+++ b/events.cpp
@@ -0,0 +1,99 @@
+/**
+ * Copyright © 2017 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "events.hpp"
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor
+{
+namespace inventory
+{
+namespace manager
+{
+namespace filters
+{
+namespace details
+{
+namespace property_condition
+{
+
+bool PropertyConditionBase::operator()(
+ sdbusplus::bus::bus& bus,
+ sdbusplus::message::message&,
+ Manager&) const
+{
+ std::string host;
+
+ if (_service)
+ {
+ host.assign(_service);
+ }
+ else
+ {
+ auto mapperCall = bus.new_method_call(
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/ObjectMapper",
+ "xyz.openbmc_project.ObjectMapper",
+ "GetObject");
+ mapperCall.append(_path);
+ mapperCall.append(std::vector<std::string>({_iface}));
+
+ auto mapperResponseMsg = bus.call(mapperCall);
+ if (mapperResponseMsg.is_method_error())
+ {
+ return false;
+ }
+
+ std::map<std::string, std::vector<std::string>> mapperResponse;
+ mapperResponseMsg.read(mapperResponse);
+
+ if (mapperResponse.begin() == mapperResponse.end())
+ {
+ return false;
+ }
+
+ host = mapperResponse.begin()->first;
+
+ if (host == bus.get_unique_name())
+ {
+ // TODO I can't call myself here.
+ return false;
+ }
+ }
+ auto hostCall = bus.new_method_call(
+ host.c_str(),
+ _path.c_str(),
+ "org.freedesktop.DBus.Properties",
+ "Get");
+ hostCall.append(_iface);
+ hostCall.append(_property);
+
+ auto hostResponseMsg = bus.call(hostCall);
+ if (hostResponseMsg.is_method_error())
+ {
+ return false;
+ }
+
+ return eval(hostResponseMsg);
+}
+
+} // namespace property_condition
+} // namespace details
+} // namespace filters
+} // namespace manager
+} // namespace inventory
+} // namespace phosphor
+
+// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/events.hpp b/events.hpp
index 80fcdae..45122a0 100644
--- a/events.hpp
+++ b/events.hpp
@@ -154,6 +154,120 @@ struct PropertyChangedCondition
U _condition;
};
+/** @struct PropertyConditionBase
+ * @brief Match filter functor that tests a property value.
+ *
+ * Base class for PropertyCondition - factored out code that
+ * doesn't need to be templated.
+ */
+struct PropertyConditionBase
+{
+ PropertyConditionBase() = delete;
+ virtual ~PropertyConditionBase() = default;
+ PropertyConditionBase(const PropertyConditionBase&) = delete;
+ PropertyConditionBase& operator=(const PropertyConditionBase&) = delete;
+ PropertyConditionBase(PropertyConditionBase&&) = default;
+ PropertyConditionBase& operator=(PropertyConditionBase&&) = default;
+
+ /** @brief Constructor
+ *
+ * The service argument can be nullptr. If something
+ * else is provided the function will call the the
+ * service directly. If omitted, the function will
+ * look up the service in the ObjectMapper.
+ *
+ * @param path - The path of the object containing
+ * the property to be tested.
+ * @param iface - The interface hosting the property
+ * to be tested.
+ * @param property - The property to be tested.
+ * @param service - The DBus service hosting the object.
+ */
+ PropertyConditionBase(
+ const char* path,
+ const char* iface,
+ const char* property,
+ const char* service) :
+ _path(path),
+ _iface(iface),
+ _property(property),
+ _service(service) {}
+
+ /** @brief Forward comparison to type specific implementation. */
+ virtual bool eval(sdbusplus::message::message&) const = 0;
+
+ /** @brief Test a property value.
+ *
+ * Make a DBus call and test the value of any property.
+ */
+ bool operator()(
+ sdbusplus::bus::bus&,
+ sdbusplus::message::message&,
+ Manager&) const;
+
+ private:
+ std::string _path;
+ std::string _iface;
+ std::string _property;
+ const char* _service;
+};
+
+/** @struct PropertyCondition
+ * @brief Match filter functor that tests a property value.
+ *
+ * @tparam T - The type of the property being tested.
+ * @tparam U - The type of the condition checking functor.
+ */
+template <typename T, typename U>
+struct PropertyCondition final : public PropertyConditionBase
+{
+ PropertyCondition() = delete;
+ ~PropertyCondition() = default;
+ PropertyCondition(const PropertyCondition&) = delete;
+ PropertyCondition& operator=(const PropertyCondition&) = delete;
+ PropertyCondition(PropertyCondition&&) = default;
+ PropertyCondition& operator=(PropertyCondition&&) = default;
+
+ /** @brief Constructor
+ *
+ * The service argument can be nullptr. If something
+ * else is provided the function will call the the
+ * service directly. If omitted, the function will
+ * look up the service in the ObjectMapper.
+ *
+ * @param path - The path of the object containing
+ * the property to be tested.
+ * @param iface - The interface hosting the property
+ * to be tested.
+ * @param property - The property to be tested.
+ * @param condition - The test to run on the property.
+ * @param service - The DBus service hosting the object.
+ */
+ PropertyCondition(
+ const char* path,
+ const char* iface,
+ const char* property,
+ U&& condition,
+ const char* service) :
+ PropertyConditionBase(path, iface, property, service),
+ _condition(std::forward<decltype(condition)>(condition)) {}
+
+ /** @brief Test a property value.
+ *
+ * Make a DBus call and test the value of any property.
+ */
+ bool eval(sdbusplus::message::message& msg) const override
+ {
+ sdbusplus::message::variant<T> value;
+ msg.read(value);
+ return _condition(
+ std::forward<T>(value.template get<T>()));
+ }
+
+ private:
+ U _condition;
+};
+
} // namespace property_condition
} // namespace details
@@ -173,6 +287,24 @@ auto propertyChangedTo(
iface, property, std::move(condition));
}
+/** @brief Implicit type deduction for constructing PropertyCondition. */
+template <typename T>
+auto propertyIs(
+ const char* path,
+ const char* iface,
+ const char* property,
+ T&& val,
+ const char* service = nullptr)
+{
+ auto condition = [val = std::forward<T>(val)](T && arg)
+ {
+ return arg == val;
+ };
+ using U = decltype(condition);
+ return details::property_condition::PropertyCondition<T, U>(
+ path, iface, property, std::move(condition), service);
+}
+
} // namespace filters
} // namespace manager
} // namespace inventory
diff --git a/example/events.d/match2.yaml b/example/events.d/match2.yaml
index 047462d..a4e98f0 100644
--- a/example/events.d/match2.yaml
+++ b/example/events.d/match2.yaml
@@ -49,4 +49,36 @@ events:
paths:
- /deleteme3
+ - name: Example Match
+ description: >
+ Destroys the /deleteme3 object when the value of
+ ExampleProperty3 on /testing/trigger4 is 99
+ and the value of ExampleProperty2 on /testing/trigger4
+ changes to "123".
+ type: match
+ signatures:
+ - type: signal
+ path: /testing/trigger4
+ interface: org.freedesktop.DBus.Properties
+ member: PropertiesChanged
+ filters:
+ - name: propertyChangedTo
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty2
+ value:
+ value: 123
+ type: string
+ - name: propertyIs
+ path: /testing/trigger4
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty3
+ service: phosphor.inventory.test.example
+ value:
+ value: 99
+ type: int64
+ actions:
+ - name: destroyObjects
+ paths:
+ - /deleteme3
+
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/test/test.cpp b/test/test.cpp
index bd75dbb..e4b6a45 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -38,6 +38,9 @@ const auto trigger2 = sdbusplus::message::object_path(EXAMPLE_ROOT +
"/trigger2"s);
const auto trigger3 = sdbusplus::message::object_path(EXAMPLE_ROOT +
"/trigger3"s);
+const auto trigger4 = sdbusplus::message::object_path(EXAMPLE_ROOT +
+ "/trigger4"s);
+
const sdbusplus::message::object_path relDeleteMeOne{"/deleteme1"};
const sdbusplus::message::object_path relDeleteMeTwo{"/deleteme2"};
@@ -73,6 +76,8 @@ struct ExampleService
ExampleIface1, ExampleIface2 > t2(bus, trigger2.str.c_str());
sdbusplus::server::object::object <
ExampleIface1, ExampleIface2 > t3(bus, trigger3.str.c_str());
+ sdbusplus::server::object::object <
+ ExampleIface1, ExampleIface2 > t4(bus, trigger4.str.c_str());
while (!shutdown)
{
@@ -233,6 +238,79 @@ void runTests()
assert(!moreSignals);
}
+ // Validate the propertyIs filter.
+ {
+ // Create an object to be deleted.
+ {
+ auto m = notify();
+ m.append(relDeleteMeThree);
+ m.append(obj);
+ b.call(m);
+ }
+
+ // Validate that the action does not run if the property doesn't match.
+ {
+ SignalQueue queue(
+ "path='" + root + "',member='InterfacesRemoved'");
+ auto m = set(trigger4.str);
+ m.append("xyz.openbmc_project.Example.Iface2");
+ m.append("ExampleProperty2");
+ m.append(sdbusplus::message::variant<std::string>("123"));
+ b.call(m);
+ auto sig{queue.pop()};
+ assert(!sig);
+ }
+
+ // Validate that the action does run if the property matches.
+ {
+ // Set ExampleProperty2 to something else to the 123 filter
+ // matches.
+ SignalQueue queue(
+ "path='" + root + "',member='InterfacesRemoved'");
+ auto m = set(trigger4.str);
+ m.append("xyz.openbmc_project.Example.Iface2");
+ m.append("ExampleProperty2");
+ m.append(sdbusplus::message::variant<std::string>("xyz"));
+ b.call(m);
+ auto sig{queue.pop()};
+ assert(!sig);
+ }
+ {
+ // Set ExampleProperty3 to 99.
+ SignalQueue queue(
+ "path='" + root + "',member='InterfacesRemoved'");
+ auto m = set(trigger4.str);
+ m.append("xyz.openbmc_project.Example.Iface2");
+ m.append("ExampleProperty3");
+ m.append(sdbusplus::message::variant<int64_t>(99));
+ b.call(m);
+ auto sig{queue.pop()};
+ assert(!sig);
+ }
+ {
+ SignalQueue queue(
+ "path='" + root + "',member='InterfacesRemoved'");
+ auto m = set(trigger4.str);
+ m.append("xyz.openbmc_project.Example.Iface2");
+ m.append("ExampleProperty2");
+ m.append(sdbusplus::message::variant<std::string>("123"));
+ b.call(m);
+
+ sdbusplus::message::object_path sigpath;
+ std::vector<std::string> interfaces;
+ {
+ std::vector<std::string> interfaces;
+ auto sig{queue.pop()};
+ assert(sig);
+ sig.read(sigpath);
+ assert(sigpath == deleteMeThree);
+ sig.read(interfaces);
+ std::sort(interfaces.begin(), interfaces.end());
+ assert(hasInterfaces(interfaces, obj));
+ }
+ }
+ }
+
// Make sure DBus signals are handled.
{
// Create some objects to be deleted by an action.
OpenPOWER on IntegriCloud