summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrad Bishop <bradleyb@fuzziesquirrel.com>2017-05-25 23:38:37 -0400
committerBrad Bishop <bradleyb@fuzziesquirrel.com>2017-06-19 16:26:48 -0400
commit0df00be00999bc3285b8b0a401b48e42fb862250 (patch)
treef1c9c332b7fede66daf5b42abc283fdbe190d98c /src
parent01079892b1768be2b2f28a6a8ac56422792ff930 (diff)
downloadphosphor-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.am3
-rw-r--r--src/example/example.yaml15
-rw-r--r--src/method.hpp138
-rwxr-xr-xsrc/pdmgen.py80
-rw-r--r--src/sdbusplus.hpp22
-rw-r--r--src/templates/generated.mako.hpp1
-rw-r--r--src/templates/method.mako.cpp6
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])})\
OpenPOWER on IntegriCloud