Blob Blame History Raw
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