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