summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrad Bishop <bradleyb@fuzziesquirrel.com>2017-01-30 08:52:26 -0500
committerPatrick Williams <patrick@stwcx.xyz>2017-02-15 17:43:18 +0000
commitd0f48adcb11d1640cc906446f6222c2b95052cb5 (patch)
treee13a71aa31714f18817561fe1d3e6c38be6998f4
parentc1f4798d36e63842c97692ca1a36c0975da18c09 (diff)
downloadphosphor-inventory-manager-d0f48adcb11d1640cc906446f6222c2b95052cb5.tar.gz
phosphor-inventory-manager-d0f48adcb11d1640cc906446f6222c2b95052cb5.zip
Add path conditions
Add support to setProperty and destroyObject to conditionally perform their action based on the result of a condition testing functor. Change-Id: I67ded31f4a7ee0f7a29bb6edc06ebf9249cdc070 Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
-rw-r--r--README.md15
-rw-r--r--example/events.d/match1.yaml37
-rw-r--r--example/events.d/match2.yaml36
-rw-r--r--functor.cpp14
-rw-r--r--functor.hpp72
-rwxr-xr-xpimgen.py38
-rw-r--r--types.hpp3
7 files changed, 192 insertions, 23 deletions
diff --git a/README.md b/README.md
index 08cba81..c97db6d 100644
--- a/README.md
+++ b/README.md
@@ -86,6 +86,9 @@ 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.
+propertyIs can be used in an action condition context when the
+action operates on a dbus object path.
+
---
**actions**
@@ -105,6 +108,11 @@ The available actions provided by PIM are:
Supported arguments for the destroyObject action are:
* paths - The paths of the objects to remove from DBus.
+* conditions - An array of conditions.
+
+Conditions are tested and logically ANDed. If the conditions do not
+pass, the object is not destroyed. Any condition that accepts a path
+parameter is supported.
----
**setProperty**
@@ -112,8 +120,13 @@ Supported arguments for the destroyObject action are:
Supported arguments for the setProperty action are:
* interface - The interface hosting the property to be set.
* property - The property to set.
-* path - The object hosting the property to be set.
+* paths - The objects hosting the property to be set.
* value - The value to set.
+* conditions - An array of conditions.
+
+Conditions are tested and logically ANDed. If the conditions do not
+pass, the property is not set. Any condition that accepts a path
+parameter is supported.
----
**createObjects**
diff --git a/example/events.d/match1.yaml b/example/events.d/match1.yaml
index 7133271..3763093 100644
--- a/example/events.d/match1.yaml
+++ b/example/events.d/match1.yaml
@@ -89,4 +89,41 @@ events:
value: foo
type: string
+ - name: conditional setProperty example
+ description: >
+ Sets the ExampleProperty1 on the /changeme object when
+ the value of ExampleProperty3 on /testing/trigger7
+ changes to 10 and the value of the ExampleProperty3
+ value on /changeme is 22.
+ type: match
+ signatures:
+ - type: signal
+ path: /testing/trigger7
+ interface: org.freedesktop.DBus.Properties
+ member: PropertiesChanged
+ filters:
+ - name: propertyChangedTo
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty3
+ value:
+ value: 10
+ type: int64
+ actions:
+ - name: setProperty
+ interface: xyz.openbmc_project.Example.Iface1
+ property: ExampleProperty1
+ paths:
+ - /changeme
+ value:
+ type: string
+ value: changed
+ conditions:
+ - name: propertyIs
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty3
+ value:
+ value: 22
+ type: int64
+
+
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/example/events.d/match2.yaml b/example/events.d/match2.yaml
index 31836b0..6fbe496 100644
--- a/example/events.d/match2.yaml
+++ b/example/events.d/match2.yaml
@@ -82,4 +82,40 @@ events:
paths:
- /deleteme3
+ - name: conditional destroyObject example
+ description: >
+ Destroys the /deleteme3 object when the value of
+ ExampleProperty3 on /testing/trigger6
+ changes to 10 and the value of the ExampleProperty3
+ value on /deleteme3 is 22.
+ Destroys the /deleteme4 object when the value of
+ ExampleProperty3 on /testing/trigger6
+ changes to 10 and the value of the ExampleProperty3
+ value on /deleteme4 is 22.
+ type: match
+ signatures:
+ - type: signal
+ path: /testing/trigger6
+ interface: org.freedesktop.DBus.Properties
+ member: PropertiesChanged
+ filters:
+ - name: propertyChangedTo
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty3
+ value:
+ value: 10
+ type: int64
+ actions:
+ - name: destroyObjects
+ paths:
+ - /deleteme3
+ - /deleteme4
+ conditions:
+ - name: propertyIs
+ interface: xyz.openbmc_project.Example.Iface2
+ property: ExampleProperty3
+ value:
+ value: 22
+ type: int64
+
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/functor.cpp b/functor.cpp
index a657257..253f0e9 100644
--- a/functor.cpp
+++ b/functor.cpp
@@ -24,10 +24,18 @@ namespace manager
{
namespace functor
{
-
bool PropertyConditionBase::operator()(
sdbusplus::bus::bus& bus,
sdbusplus::message::message&,
+ Manager& mgr) const
+{
+ std::string path(_path);
+ return (*this)(path, bus, mgr);
+}
+
+bool PropertyConditionBase::operator()(
+ const std::string& path,
+ sdbusplus::bus::bus& bus,
Manager&) const
{
std::string host;
@@ -43,7 +51,7 @@ bool PropertyConditionBase::operator()(
"/xyz/openbmc_project/ObjectMapper",
"xyz.openbmc_project.ObjectMapper",
"GetObject");
- mapperCall.append(_path);
+ mapperCall.append(path);
mapperCall.append(std::vector<std::string>({_iface}));
auto mapperResponseMsg = bus.call(mapperCall);
@@ -70,7 +78,7 @@ bool PropertyConditionBase::operator()(
}
auto hostCall = bus.new_method_call(
host.c_str(),
- _path.c_str(),
+ path.c_str(),
"org.freedesktop.DBus.Properties",
"Get");
hostCall.append(_iface);
diff --git a/functor.hpp b/functor.hpp
index 265e467..50fdcfa 100644
--- a/functor.hpp
+++ b/functor.hpp
@@ -45,15 +45,51 @@ auto make_filter(T&& filter)
return Filter(std::forward<T>(filter));
}
+/** @brief make_path_condition
+ *
+ * Adapt a path_condition function object.
+ *
+ * @param[in] filter - The functor being adapted.
+ * @returns - The adapted functor.
+ *
+ * @tparam T - The type of the functor being adapted.
+ */
+template <typename T>
+auto make_path_condition(T&& condition)
+{
+ return PathCondition(std::forward<T>(condition));
+}
+
+template <typename T, typename ...Args>
+auto callArrayWithStatus(T&& container, Args&& ...args)
+{
+ for (auto f : container)
+ {
+ if (!f(std::forward<Args>(args)...))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
namespace functor
{
/** @brief Destroy objects action. */
-inline auto destroyObjects(std::vector<const char*>&& paths)
+inline auto destroyObjects(
+ std::vector<const char*>&& paths,
+ std::vector<PathCondition>&& conditions)
{
- return [ = ](auto&, auto & m)
+ return [ = ](auto & b, auto & m)
{
- m.destroyObjects(paths);
+ for (const auto& p : paths)
+ {
+ if (callArrayWithStatus(conditions, p, b, m))
+ {
+ m.destroyObjects({p});
+ }
+ }
};
}
@@ -88,20 +124,27 @@ inline auto createObjects(
*/
template <typename T, typename U, typename V>
auto setProperty(
- std::vector<const char*>&& paths, const char* iface,
- U&& member, V&& value)
+ std::vector<const char*>&& paths,
+ std::vector<PathCondition>&& conditions,
+ const char* iface,
+ U&& member,
+ V&& value)
{
// The manager is the only parameter passed to actions.
// Bind the path, interface, interface member function pointer,
// and value to a lambda. When it is called, forward the
// path, interface and value on to the manager member function.
- return [paths, iface, member,
- value = std::forward<V>(value)](auto&, auto & m)
+ return [paths, conditions = conditions, iface,
+ member,
+ value = std::forward<V>(value)](auto & b, auto & m)
{
for (auto p : paths)
{
- m.template invokeMethod<T>(
- p, iface, member, value);
+ if (callArrayWithStatus(conditions, p, b, m))
+ {
+ m.template invokeMethod<T>(
+ p, iface, member, value);
+ }
}
};
}
@@ -199,7 +242,7 @@ struct PropertyConditionBase
const char* iface,
const char* property,
const char* service) :
- _path(path),
+ _path(path ? path : std::string()),
_iface(iface),
_property(property),
_service(service) {}
@@ -216,6 +259,15 @@ struct PropertyConditionBase
sdbusplus::message::message&,
Manager&) const;
+ /** @brief Test a property value.
+ *
+ * Make a DBus call and test the value of any property.
+ */
+ bool operator()(
+ const std::string&,
+ sdbusplus::bus::bus&,
+ Manager&) const;
+
private:
std::string _path;
std::string _iface;
diff --git a/pimgen.py b/pimgen.py
index 2193c90..deaeb59 100755
--- a/pimgen.py
+++ b/pimgen.py
@@ -222,6 +222,14 @@ class Action(MethodCall):
super(Action, self).__init__(**kw)
+class PathCondition(MethodCall):
+ '''Convenience type for path conditions'''
+
+ def __init__(self, **kw):
+ kw['name'] = 'make_path_condition'
+ super(PathCondition, self).__init__(**kw)
+
+
class CreateObjects(MethodCall):
'''Assemble a createObjects functor.'''
@@ -262,8 +270,13 @@ class DestroyObjects(MethodCall):
def __init__(self, **kw):
values = [{'value': x, 'type': 'string'} for x in kw.pop('paths')]
+ conditions = [
+ Event.functor_map[
+ x['name']](**x) for x in kw.pop('conditions', [])]
+ conditions = [PathCondition(args=[x]) for x in conditions]
args = [InitializerList(
values=[TrivialArgument(**x) for x in values])]
+ args.append(InitializerList(values=conditions))
kw['args'] = args
kw['namespace'] = ['functor']
super(DestroyObjects, self).__init__(**kw)
@@ -292,6 +305,12 @@ class SetProperty(MethodCall):
args.append(InitializerList(
values=[TrivialArgument(**x) for x in paths]))
+ conditions = [
+ Event.functor_map[
+ x['name']](**x) for x in kw.pop('conditions', [])]
+ conditions = [PathCondition(args=[x]) for x in conditions]
+
+ args.append(InitializerList(values=conditions))
args.append(TrivialArgument(value=str(iface), type='string'))
args.append(TrivialArgument(
value=member, decorators=[Cast('static', member_cast)]))
@@ -323,7 +342,13 @@ class PropertyIs(MethodCall):
def __init__(self, **kw):
args = []
- args.append(TrivialArgument(value=kw.pop('path'), type='string'))
+ path = kw.pop('path', None)
+ if not path:
+ path = TrivialArgument(value='nullptr')
+ else:
+ path = TrivialArgument(value=path, type='string')
+
+ args.append(path)
args.append(TrivialArgument(value=kw.pop('interface'), type='string'))
args.append(TrivialArgument(value=kw.pop('property'), type='string'))
args.append(TrivialArgument(
@@ -342,22 +367,19 @@ class PropertyIs(MethodCall):
class Event(MethodCall):
'''Assemble an inventory manager event.'''
- action_map = {
+ functor_map = {
'destroyObjects': DestroyObjects,
'createObjects': CreateObjects,
- 'setProperty': SetProperty,
- }
-
- filter_map = {
'propertyChangedTo': PropertyChanged,
'propertyIs': PropertyIs,
+ 'setProperty': SetProperty,
}
def __init__(self, **kw):
self.summary = kw.pop('name')
filters = [
- self.filter_map[x['name']](**x) for x in kw.pop('filters', [])]
+ self.functor_map[x['name']](**x) for x in kw.pop('filters', [])]
filters = [Filter(args=[x]) for x in filters]
filters = Vector(
templates=[Template(name='Filter', namespace=[])],
@@ -377,7 +399,7 @@ class Event(MethodCall):
action_type = Template(name='Action', namespace=[])
action_args = [
- self.action_map[x['name']](**x) for x in kw.pop('actions', [])]
+ self.functor_map[x['name']](**x) for x in kw.pop('actions', [])]
action_args = [Action(args=[x]) for x in action_args]
actions = Vector(
templates=[action_type],
diff --git a/types.hpp b/types.hpp
index d2105aa..52a00ee 100644
--- a/types.hpp
+++ b/types.hpp
@@ -32,7 +32,8 @@ using Object = ObjectType<InterfaceVariantType>;
using Action = std::function<void (sdbusplus::bus::bus&, Manager&)>;
using Filter = std::function <
bool (sdbusplus::bus::bus&, sdbusplus::message::message&, Manager&) >;
-
+using PathCondition = std::function <
+ bool (const std::string&, sdbusplus::bus::bus&, Manager&) >;
} // namespace manager
} // namespace inventory
} // namespace phosphor
OpenPOWER on IntegriCloud