diff options
author | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2017-01-30 08:52:26 -0500 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-02-15 17:43:18 +0000 |
commit | d0f48adcb11d1640cc906446f6222c2b95052cb5 (patch) | |
tree | e13a71aa31714f18817561fe1d3e6c38be6998f4 | |
parent | c1f4798d36e63842c97692ca1a36c0975da18c09 (diff) | |
download | phosphor-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.md | 15 | ||||
-rw-r--r-- | example/events.d/match1.yaml | 37 | ||||
-rw-r--r-- | example/events.d/match2.yaml | 36 | ||||
-rw-r--r-- | functor.cpp | 14 | ||||
-rw-r--r-- | functor.hpp | 72 | ||||
-rwxr-xr-x | pimgen.py | 38 | ||||
-rw-r--r-- | types.hpp | 3 |
7 files changed, 192 insertions, 23 deletions
@@ -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; @@ -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], @@ -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 |