From 86062536d4a314c0d628791640127238a2952be4 Mon Sep 17 00:00:00 2001
From: Jakub Filak <jfilak@redhat.com>
Date: Tue, 22 Oct 2013 15:45:34 +0200
Subject: [ABRT PATCH 59/76] factor out D-Bus notification to a python script
This patch is a part of our effort to move application logic from
configuration files to executables.
Related to #684
Signed-off-by: Jakub Filak <jfilak@redhat.com>
---
doc/Makefile.am | 1 +
doc/abrt-action-notify.txt | 38 ++++++++++
src/dbus/dbus_event.conf | 19 +----
src/plugins/Makefile.am | 6 +-
src/plugins/abrt-action-notify | 164 +++++++++++++++++++++++++++++++++++++++++
5 files changed, 211 insertions(+), 17 deletions(-)
create mode 100644 doc/abrt-action-notify.txt
create mode 100644 src/plugins/abrt-action-notify
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 1ca52b5..8b14517 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -16,6 +16,7 @@ MAN1_TXT += abrt-action-analyze-vulnerability.txt
MAN1_TXT += abrt-action-install-debuginfo.txt
MAN1_TXT += abrt-action-list-dsos.txt
MAN1_TXT += abrt-action-perform-ccpp-analysis.txt
+MAN1_TXT += abrt-action-notify.txt
MAN1_TXT += abrt-applet.txt
MAN1_TXT += abrt-dump-oops.txt
MAN1_TXT += abrt-dump-xorg.txt
diff --git a/doc/abrt-action-notify.txt b/doc/abrt-action-notify.txt
new file mode 100644
index 0000000..c5bd7b0
--- /dev/null
+++ b/doc/abrt-action-notify.txt
@@ -0,0 +1,38 @@
+abrt-action-notify(1)
+===================
+
+NAME
+----
+abrt-action-notify - Announces a new occurrence of problem via all accessible channels
+
+SYNOPSIS
+--------
+'abrt-action-notify' [-h] [-d PROBLEM_DIR]
+
+DESCRIPTION
+-----------
+The current implementation emits a D-Bus signal on System bus in path
+/org/freedesktop/problems of org.freedesktop.problems interface for Crash
+member.
+
+Integration with ABRT events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+'abrt-action-notify' is used to notify new problems and consecutive occurrences
+of a single problem for all crash types.
+
+------------
+EVENT=notify package!=
+ abrt-action-notify
+------------
+
+OPTIONS
+-------
+-d, --problem-dir PROBLEM_DIR::
+ Problem directory [Default: current directory]
+
+-h, --help::
+ Show help message
+
+AUTHORS
+-------
+* ABRT team
diff --git a/src/dbus/dbus_event.conf b/src/dbus/dbus_event.conf
index 4d24fef..499e484 100644
--- a/src/dbus/dbus_event.conf
+++ b/src/dbus/dbus_event.conf
@@ -1,16 +1,5 @@
-EVENT=notify package!= uid!=
- dbus-send --system --type=signal /org/freedesktop/problems org.freedesktop.problems.Crash \
- string:"`cat package`" string:"$DUMP_DIR" string:"`cat uid`"
-
-EVENT=notify package!= uid=
- dbus-send --system --type=signal /org/freedesktop/problems org.freedesktop.problems.Crash \
- string:"`cat package`" string:"$DUMP_DIR"
-
-EVENT=notify-dup package!= uid!=
- dbus-send --system --type=signal /org/freedesktop/problems org.freedesktop.problems.Crash \
- string:"`cat package`" string:"$DUMP_DIR" string:"`cat uid`"
-
-EVENT=notify-dup package!= uid=
- dbus-send --system --type=signal /org/freedesktop/problems org.freedesktop.problems.Crash \
- string:"`cat package`" string:"$DUMP_DIR"
+EVENT=notify package!=
+ abrt-action-notify -d $DUMP_DIR
+EVENT=notify-dup package!=
+ abrt-action-notify -d $DUMP_DIR
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index fbda305..370d5fd 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -8,7 +8,8 @@ bin_SCRIPTS = \
abrt-action-list-dsos \
abrt-action-perform-ccpp-analysis \
abrt-action-save-kernel-data \
- abrt-action-analyze-ccpp-local
+ abrt-action-analyze-ccpp-local \
+ abrt-action-notify
bin_PROGRAMS = \
abrt-watch-log \
@@ -73,7 +74,8 @@ PYTHON_FILES = \
abrt-action-analyze-core \
abrt-action-analyze-vulnerability \
abrt-action-analyze-vmcore.in \
- abrt-action-perform-ccpp-analysis.in
+ abrt-action-perform-ccpp-analysis.in \
+ abrt-action-notify
EXTRA_DIST = \
$(PYTHON_FILES) \
diff --git a/src/plugins/abrt-action-notify b/src/plugins/abrt-action-notify
new file mode 100644
index 0000000..722d7f6
--- /dev/null
+++ b/src/plugins/abrt-action-notify
@@ -0,0 +1,164 @@
+#!/usr/bin/python
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+import os
+import sys
+from argparse import ArgumentParser
+
+import dbus
+import dbus.lowlevel
+
+import report
+from reportclient import (RETURN_OK,
+ RETURN_FAILURE)
+
+CD_DUMPDIR = "Directory"
+FILENAME_PACKAGE = "package"
+FILENAME_UID = "uid"
+FILENAME_UUID = "uuid"
+FILENAME_DUPHASH = "duphash"
+
+def emit_crash_dbus_signal(problem_data):
+ """Emits a Crash signal on D-Bus Problem bus
+
+ Emits a signal with 5 members:
+ package -- value of 'package' element in problem_data
+ problem_id -- value of 'Directory' element in problem_data
+ uid -- empty string if 'uid' element is not present in problem_data
+
+
+
+ Keyword arguments:
+ problem_data -- problem data of notified problems
+
+ Returns None as it raises an exception on error
+
+ Raises:
+ RuntimeError -- for all D-Bus related errors
+ KeyError -- if any of required elements is missing
+ """
+
+ try:
+ bus = dbus.SystemBus()
+ msg = dbus.lowlevel.SignalMessage("/org/freedesktop/problems",
+ "org.freedesktop.problems", "Crash")
+
+ # List of tuples where the first member is element name and the second
+ # member is a Boolean flag which is True if the element is required
+ arguments = ((FILENAME_PACKAGE, True), (CD_DUMPDIR, True),
+ (FILENAME_UID, False)
+ )
+
+ for elem in arguments:
+ itm = problem_data.get(elem[0])
+
+ if itm is None:
+ if elem[1]:
+ raise KeyError(elem[0])
+
+ msg.append("", signature="s")
+ else:
+ msg.append(itm[0], signature="s")
+
+
+ bus.send_message(msg)
+ except dbus.exceptions.DBusException as ex:
+ raise RuntimeError("Failed to emit D-Bus Crash signal: {0}"
+ .format(ex.message))
+ finally:
+ if bus is not None:
+ bus.close()
+
+def build_notification_problem_data(problem_dir):
+ """Loads all necessary problem elements
+
+ Problem dump directory must contain 'package' element.
+
+ Keyword arguments:
+ problem_dir -- an absolute file system path problem directory
+
+ Returns an instance of report.problem_data
+
+ Raises:
+ ValueError -- if problem_dir is not an absolute path, if problem_dir cannot
+ be opened and if any required problem element is missing.
+ """
+
+ if not os.path.isabs(problem_dir):
+ raise ValueError("problem directory must be absolute path")
+
+ prblm_dt = report.problem_data()
+
+ try:
+ dump_dir = report.dd_opendir(problem_dir, report.DD_OPEN_READONLY)
+ if not dump_dir:
+ raise ValueError("cannot open problem directory")
+
+ dd_load_flag = (report.DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
+ | report.DD_FAIL_QUIETLY_ENOENT)
+
+ package = dump_dir.load_text(FILENAME_PACKAGE, dd_load_flag)
+ if not package:
+ raise ValueError("problem directory misses '{0}'"
+ .format(FILENAME_PACKAGE))
+
+ pd_add_flag = report.CD_FLAG_TXT | report.CD_FLAG_ISNOTEDITABLE
+
+ prblm_dt.add(FILENAME_PACKAGE, package, pd_add_flag)
+ prblm_dt.add(CD_DUMPDIR, problem_dir, pd_add_flag)
+
+ for element in (FILENAME_UID, FILENAME_UUID, FILENAME_DUPHASH):
+ val = dump_dir.load_text(element, dd_load_flag)
+ if val is not None:
+ prblm_dt.add(element, val, pd_add_flag)
+ finally:
+ dump_dir.close()
+
+ return prblm_dt
+
+
+if __name__ == "__main__":
+ CMDARGS = ArgumentParser(
+ description=("Announce a new or duplicated problem via"
+ " all accessible channels"))
+ CMDARGS.add_argument("-d", "--problem-dir",
+ type=str, required=True,
+ help="An absolute path to a new or duplicated problem directory")
+
+ OPTIONS = CMDARGS.parse_args()
+
+ DIR_PATH = OPTIONS.problem_dir
+
+ try:
+ PD = build_notification_problem_data(DIR_PATH)
+ except ValueError as ex:
+ sys.stderr.write("Cannot notify '{0}': {1}\n".
+ format(DIR_PATH, ex.message))
+ sys.exit(RETURN_FAILURE)
+
+ try:
+ emit_crash_dbus_signal(PD)
+ except RuntimeError as ex:
+ sys.stderr.write("Cannot notify '{0}': {1}\n".
+ format(DIR_PATH, ex.message))
+ sys.exit(RETURN_FAILURE)
+ except KeyError as ex:
+ # this is a bug in build_notification_problem_data()
+ sys.stderr.write("BUG: problem data misses required element '{0}'"
+ .format(ex.message))
+ sys.exit(RETURN_FAILURE)
+
+ sys.exit(RETURN_OK)
+
--
1.8.3.1