diff options
author | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2017-05-25 23:38:37 -0400 |
---|---|---|
committer | Brad Bishop <bradleyb@fuzziesquirrel.com> | 2017-06-19 16:26:48 -0400 |
commit | 0df00be00999bc3285b8b0a401b48e42fb862250 (patch) | |
tree | f1c9c332b7fede66daf5b42abc283fdbe190d98c /src | |
parent | 01079892b1768be2b2f28a6a8ac56422792ff930 (diff) | |
download | phosphor-dbus-monitor-0df00be00999bc3285b8b0a401b48e42fb862250.tar.gz phosphor-dbus-monitor-0df00be00999bc3285b8b0a401b48e42fb862250.zip |
Method support
Add support for a method callback. The method callback enables
arbitrary DBus method calls. A sample use case could be
starting a systemd unit via the sytemd DBus API.
Change-Id: If25131d11497c82f862ae1f47da066c5fd8b2e2e
Signed-off-by: Brad Bishop <bradleyb@fuzziesquirrel.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/example/example.yaml | 15 | ||||
-rw-r--r-- | src/method.hpp | 138 | ||||
-rwxr-xr-x | src/pdmgen.py | 80 | ||||
-rw-r--r-- | src/sdbusplus.hpp | 22 | ||||
-rw-r--r-- | src/templates/generated.mako.hpp | 1 | ||||
-rw-r--r-- | src/templates/method.mako.cpp | 6 |
7 files changed, 264 insertions, 1 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 4d6658d..0380f6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,7 +26,8 @@ TEMPLATES = \ templates/conditional.mako.cpp \ templates/count.mako.cpp \ templates/generated.mako.hpp \ - templates/journal.mako.cpp + templates/journal.mako.cpp \ + templates/method.mako.cpp generated.hpp: $(PDMGEN) $(YAML_PATH) $(TEMPLATES) $(AM_V_GEN)$(PYTHON) ${PDMGEN} \ diff --git a/src/example/example.yaml b/src/example/example.yaml index 2066227..d76e3ad 100644 --- a/src/example/example.yaml +++ b/src/example/example.yaml @@ -78,6 +78,21 @@ severity: INFO message: Hello world from PDM! +- name: example method callback + description: > + 'The method callback invokes the specified DBus method.' + class: callback + callback: method + service: org.freedesktop.systemd1 + path: /org/freedesktop/systemd1 + interface: org.freedesktop.systemd1.Manager + method: StartUnit + args: + - value: foo.unit + type: string + - value: replace + type: string + - name: example callback group description: > 'Callbacks groups are simply named collections of other callbacks. diff --git a/src/method.hpp b/src/method.hpp new file mode 100644 index 0000000..66c19db --- /dev/null +++ b/src/method.hpp @@ -0,0 +1,138 @@ +#pragma once + +#include <experimental/tuple> +#include "callback.hpp" + +namespace phosphor +{ +namespace dbus +{ +namespace monitoring +{ +namespace detail +{ + +/** @class CallDBusMethod + * @brief Provide explicit call forwarding to + * DBusInterface::callMethodNoReply. + * + * @tparam DBusInterface - The DBus interface to use. + * @tparam MethodArgs - DBus method argument types. + */ +template <typename DBusInterface, typename ...MethodArgs> +struct CallDBusMethod +{ + static void op( + const std::string& bus, + const std::string& path, + const std::string& iface, + const std::string& method, + MethodArgs&& ...args) + { + DBusInterface::callMethodNoReply( + bus, + path, + iface, + method, + std::forward<MethodArgs>(args)...); + } +}; +} // namespace detail + +/** @class MethodBase + * @brief Invoke DBus method callback implementation. + * + * The method callback invokes the client supplied DBus method. + */ +class MethodBase : public Callback +{ + public: + MethodBase() = delete; + MethodBase(const MethodBase&) = delete; + MethodBase(MethodBase&&) = default; + MethodBase& operator=(const MethodBase&) = delete; + MethodBase& operator=(MethodBase&&) = default; + virtual ~MethodBase() = default; + MethodBase( + const std::string& b, + const std::string& p, + const std::string& i, + const std::string& m) + : Callback(), + bus(b), + path(p), + interface(i), + method(m) {} + + /** @brief Callback interface implementation. */ + void operator()() override = 0; + + protected: + const std::string& bus; + const std::string& path; + const std::string& interface; + const std::string& method; +}; + +/** @class Method + * @brief C++ type specific logic for the method callback. + * + * @tparam DBusInterface - The DBus interface to use to call the method. + * @tparam MethodArgs - DBus method argument types. + */ +template <typename DBusInterface, typename ...MethodArgs> +class Method : public MethodBase +{ + public: + Method() = delete; + Method(const Method&) = default; + Method(Method&&) = default; + Method& operator=(const Method&) = default; + Method& operator=(Method&&) = default; + ~Method() = default; + Method( + const std::string& bus, + const std::string& path, + const std::string& iface, + const std::string& method, + MethodArgs&& ... arguments) + : MethodBase(bus, path, iface, method), + args(std::forward<MethodArgs>(arguments)...) {} + + /** @brief Callback interface implementation. */ + void operator()() override + { + std::experimental::apply( + detail::CallDBusMethod<DBusInterface, MethodArgs...>::op, + std::tuple_cat( + std::make_tuple(bus), + std::make_tuple(path), + std::make_tuple(interface), + std::make_tuple(method), + args)); + } + + private: + std::tuple<MethodArgs...> args; +}; + +/** @brief Argument type deduction for constructing Method instances. */ +template <typename DBusInterface, typename ...MethodArgs> +auto makeMethod( + const std::string& bus, + const std::string& path, + const std::string& iface, + const std::string& method, + MethodArgs&& ... arguments) +{ + return std::make_unique<Method<DBusInterface, MethodArgs...>>( + bus, + path, + iface, + method, + std::forward<MethodArgs>(arguments)...); +} + +} // namespace monitoring +} // namespace dbus +} // namespace phosphor diff --git a/src/pdmgen.py b/src/pdmgen.py index 6dc6861..5d4bf29 100755 --- a/src/pdmgen.py +++ b/src/pdmgen.py @@ -635,6 +635,85 @@ class Journal(Callback, Renderer): indent=indent) +class Method(ConfigEntry, Renderer): + '''Handle the method callback config file directive.''' + + def __init__(self, *a, **kw): + self.service = kw.pop('service') + self.path = kw.pop('path') + self.interface = kw.pop('interface') + self.method = kw.pop('method') + self.args = [TrivialArgument(**x) for x in kw.pop('args', {})] + super(Method, self).__init__(**kw) + + def factory(self, objs): + args = { + 'class': 'interface', + 'interface': 'element', + 'name': self.service + } + add_unique(ConfigEntry( + configfile=self.configfile, **args), objs) + + args = { + 'class': 'pathname', + 'pathname': 'element', + 'name': self.path + } + add_unique(ConfigEntry( + configfile=self.configfile, **args), objs) + + args = { + 'class': 'interface', + 'interface': 'element', + 'name': self.interface + } + add_unique(ConfigEntry( + configfile=self.configfile, **args), objs) + + args = { + 'class': 'propertyname', + 'propertyname': 'element', + 'name': self.method + } + add_unique(ConfigEntry( + configfile=self.configfile, **args), objs) + + super(Method, self).factory(objs) + + def setup(self, objs): + '''Resolve elements.''' + + self.service = get_index( + objs, + 'interface', + self.service) + + self.path = get_index( + objs, + 'pathname', + self.path) + + self.interface = get_index( + objs, + 'interface', + self.interface) + + self.method = get_index( + objs, + 'propertyname', + self.method) + + super(Method, self).setup(objs) + + def construct(self, loader, indent): + return self.render( + loader, + 'method.mako.cpp', + c=self, + indent=indent) + + class CallbackGraphEntry(Group): '''An entry in a traversal list for groups of callbacks.''' @@ -724,6 +803,7 @@ class Everything(Renderer): 'callback': { 'journal': Journal, 'group': GroupOfCallbacks, + 'method': Method, }, 'condition': { 'count': CountCondition, diff --git a/src/sdbusplus.hpp b/src/sdbusplus.hpp index 7dbf44d..8afb8b5 100644 --- a/src/sdbusplus.hpp +++ b/src/sdbusplus.hpp @@ -30,6 +30,28 @@ class SDBusPlus } public: + /** @brief Invoke a method; ignore reply. */ + template <typename ...Args> + static void callMethodNoReply( + const std::string& busName, + const std::string& path, + const std::string& interface, + const std::string& method, + Args&& ... args) + { + auto reqMsg = getBus().new_method_call( + busName.c_str(), + path.c_str(), + interface.c_str(), + method.c_str()); + reqMsg.append(std::forward<Args>(args)...); + getBus().call_noreply(reqMsg); + + // TODO: openbmc/openbmc#1719 + // invoke these methods async, with a callback + // handler that checks for errors and logs. + } + /** @brief Invoke a method. */ template <typename ...Args> static auto callMethod( diff --git a/src/templates/generated.mako.hpp b/src/templates/generated.mako.hpp index 15835bf..9e89983 100644 --- a/src/templates/generated.mako.hpp +++ b/src/templates/generated.mako.hpp @@ -7,6 +7,7 @@ #include "count.hpp" #include "data_types.hpp" #include "journal.hpp" +#include "method.hpp" #include "propertywatchimpl.hpp" #include "sdbusplus.hpp" diff --git a/src/templates/method.mako.cpp b/src/templates/method.mako.cpp new file mode 100644 index 0000000..31cdf65 --- /dev/null +++ b/src/templates/method.mako.cpp @@ -0,0 +1,6 @@ +makeMethod<SDBusPlus>( +${indent(1)}ConfigInterfaces::get()[${c.service}], +${indent(1)}ConfigPaths::get()[${c.path}], +${indent(1)}ConfigInterfaces::get()[${c.interface}], +${indent(1)}ConfigProperties::get()[${c.method}], +${indent(1)}${(',\n' + indent(1)).join([val.argument(loader, indent=indent +1) for val in c.args])})\ |