Blame src/plugins/abrt-action-notify

Packit Service 8a8a03
#!/usr/bin/python3
Packit Service 8a8a03
# This program is free software; you can redistribute it and/or modify
Packit Service 8a8a03
# it under the terms of the GNU General Public License as published by
Packit Service 8a8a03
# the Free Software Foundation; either version 2 of the License, or
Packit Service 8a8a03
# (at your option) any later version.
Packit Service 8a8a03
#
Packit Service 8a8a03
# This program is distributed in the hope that it will be useful,
Packit Service 8a8a03
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 8a8a03
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 8a8a03
# GNU General Public License for more details.
Packit Service 8a8a03
#
Packit Service 8a8a03
# You should have received a copy of the GNU General Public License
Packit Service 8a8a03
# along with this program; if not, write to the Free Software
Packit Service 8a8a03
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 8a8a03
Packit Service 8a8a03
import os
Packit Service 8a8a03
import sys
Packit Service 8a8a03
from argparse import ArgumentParser
Packit Service 8a8a03
from subprocess import call
Packit Service 8a8a03
Packit Service 8a8a03
import dbus
Packit Service 8a8a03
import dbus.lowlevel
Packit Service 8a8a03
Packit Service 8a8a03
import problem
Packit Service 8a8a03
Packit Service 8a8a03
import report
Packit Service 8a8a03
from reportclient import (RETURN_OK,
Packit Service 8a8a03
                          RETURN_FAILURE,
Packit Service 8a8a03
                          RETURN_CANCEL_BY_USER,
Packit Service 8a8a03
                          RETURN_STOP_EVENT_RUN,
Packit Service 8a8a03
                          log1,
Packit Service 8a8a03
                          set_verbosity)
Packit Service 8a8a03
Packit Service 8a8a03
CD_DUMPDIR = "Directory"
Packit Service 8a8a03
FILENAME_PACKAGE = "package"
Packit Service 8a8a03
FILENAME_UID = "uid"
Packit Service 8a8a03
FILENAME_UUID = "uuid"
Packit Service 8a8a03
FILENAME_DUPHASH = "duphash"
Packit Service 8a8a03
Packit Service 8a8a03
def run_event(event_name, dump_dir_name):
Packit Service 8a8a03
    '''
Packit Service 8a8a03
    Run event with `event_name` on problem directory `dump_dir_name`
Packit Service 8a8a03
    '''
Packit Service 8a8a03
Packit Service 8a8a03
    state, ret = report.run_event_on_problem_dir(dump_dir_name, event_name)
Packit Service 8a8a03
Packit Service 8a8a03
    if ret == 0 and state.children_count == 0:
Packit Service 8a8a03
        log1("Didn't find definition of event '%s'", event_name)
Packit Service 8a8a03
        return False
Packit Service 8a8a03
Packit Service 8a8a03
    return True
Packit Service 8a8a03
Packit Service 8a8a03
def run_autoreport(problem_data, event_name):
Packit Service 8a8a03
    """Runs autoreporting event
Packit Service 8a8a03
Packit Service 8a8a03
    Requires CD_DUMPDIR key in problem_data.
Packit Service 8a8a03
Packit Service 8a8a03
    Keyword arguments:
Packit Service 8a8a03
    problem_data -- problem data of notified problems
Packit Service 8a8a03
Packit Service 8a8a03
    Returns None as it raises an exception on error
Packit Service 8a8a03
Packit Service 8a8a03
    Raises:
Packit Service 8a8a03
    KeyError -- if any of required elements is missing
Packit Service 8a8a03
    RuntimeError -- if event run fails
Packit Service 8a8a03
    """
Packit Service 8a8a03
Packit Service 8a8a03
    dir_name = problem_data.get(CD_DUMPDIR)
Packit Service 8a8a03
    if dir_name is None:
Packit Service 8a8a03
        raise KeyError(CD_DUMPDIR)
Packit Service 8a8a03
Packit Service 8a8a03
    log1("Running autoreporting event: '{0}'".format(event_name))
Packit Service 8a8a03
Packit Service 8a8a03
    res, ret  = report.run_event_on_problem_dir(dir_name[0], event_name)
Packit Service 8a8a03
Packit Service 8a8a03
    if res.children_count == 0 and ret == 0:
Packit Service 8a8a03
        raise RuntimeError("No processing is specified for event '{0}'"
Packit Service 8a8a03
                .format(event_name))
Packit Service 8a8a03
Packit Service 8a8a03
    if not ret in [RETURN_OK, RETURN_CANCEL_BY_USER, RETURN_STOP_EVENT_RUN]:
Packit Service 8a8a03
        raise RuntimeError("Event '{0}' exited with {1}"
Packit Service 8a8a03
                .format(event_name, ret))
Packit Service 8a8a03
Packit Service 8a8a03
def emit_crash_dbus_signal(problem_data):
Packit Service 8a8a03
    """Emits a Crash signal on D-Bus Problem bus
Packit Service 8a8a03
Packit Service 8a8a03
    Emits a signal with 5 members:
Packit Service 8a8a03
        package -- value of 'package' element in problem_data
Packit Service 8a8a03
        problem_id -- value of 'Directory' element in problem_data
Packit Service 8a8a03
        uid -- empty string if 'uid' element is not present in problem_data
Packit Service 8a8a03
        uuid -- empty string if 'uuid' element is not present in problem_data
Packit Service 8a8a03
        duphash -- empty string if 'duphash' element is not present in problem_data
Packit Service 8a8a03
Packit Service 8a8a03
    Keyword arguments:
Packit Service 8a8a03
    problem_data -- problem data of notified problems
Packit Service 8a8a03
Packit Service 8a8a03
    Returns None as it raises an exception on error
Packit Service 8a8a03
Packit Service 8a8a03
    Raises:
Packit Service 8a8a03
    RuntimeError -- for all D-Bus related errors
Packit Service 8a8a03
    KeyError -- if any of required elements is missing
Packit Service 8a8a03
    """
Packit Service 8a8a03
Packit Service 8a8a03
    bus = None
Packit Service 8a8a03
    try:
Packit Service 8a8a03
        bus = dbus.SystemBus()
Packit Service 8a8a03
        msg = dbus.lowlevel.SignalMessage("/org/freedesktop/problems",
Packit Service 8a8a03
                "org.freedesktop.problems", "Crash")
Packit Service 8a8a03
Packit Service 8a8a03
        # List of tuples where the first member is element name and the second
Packit Service 8a8a03
        # member is a Boolean flag which is True if the element is required
Packit Service 8a8a03
        arguments = ((FILENAME_PACKAGE, False), (CD_DUMPDIR, True),
Packit Service 8a8a03
                (FILENAME_UID, False), (FILENAME_UUID, False),
Packit Service 8a8a03
                (FILENAME_DUPHASH, False))
Packit Service 8a8a03
Packit Service 8a8a03
        for elem in arguments:
Packit Service 8a8a03
            itm = problem_data.get(elem[0])
Packit Service 8a8a03
Packit Service 8a8a03
            if itm is None:
Packit Service 8a8a03
                if elem[1]:
Packit Service 8a8a03
                    raise KeyError(elem[0])
Packit Service 8a8a03
Packit Service 8a8a03
                msg.append("", signature="s")
Packit Service 8a8a03
            else:
Packit Service 8a8a03
                msg.append(itm[0], signature="s")
Packit Service 8a8a03
Packit Service 8a8a03
Packit Service 8a8a03
        bus.send_message(msg)
Packit Service 8a8a03
    except dbus.exceptions.DBusException as ex:
Packit Service 8a8a03
        raise RuntimeError("Failed to emit D-Bus Crash signal: {0}"
Packit Service 8a8a03
                .format(str(ex)))
Packit Service 8a8a03
    finally:
Packit Service 8a8a03
        if bus is not None:
Packit Service 8a8a03
            bus.close()
Packit Service 8a8a03
Packit Service 8a8a03
def build_notification_problem_data(problem_dir):
Packit Service 8a8a03
    """Loads all necessary problem elements
Packit Service 8a8a03
Packit Service 8a8a03
    Keyword arguments:
Packit Service 8a8a03
    problem_dir -- an absolute file system path problem directory
Packit Service 8a8a03
Packit Service 8a8a03
    Returns an instance of report.problem_data
Packit Service 8a8a03
Packit Service 8a8a03
    Raises:
Packit Service 8a8a03
    ValueError -- if problem_dir is not an absolute path, if problem_dir cannot
Packit Service 8a8a03
        be opened and if any required problem element is missing.
Packit Service 8a8a03
    """
Packit Service 8a8a03
Packit Service 8a8a03
    if not os.path.isabs(problem_dir):
Packit Service 8a8a03
        raise ValueError("problem directory must be absolute path")
Packit Service 8a8a03
Packit Service 8a8a03
    prblm_dt = report.problem_data()
Packit Service 8a8a03
Packit Service 8a8a03
    try:
Packit Service 8a8a03
        dump_dir = report.dd_opendir(problem_dir, report.DD_OPEN_READONLY)
Packit Service 8a8a03
        if not dump_dir:
Packit Service 8a8a03
            raise ValueError("cannot open problem directory")
Packit Service 8a8a03
Packit Service 8a8a03
        dd_load_flag = (report.DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
Packit Service 8a8a03
                | report.DD_FAIL_QUIETLY_ENOENT)
Packit Service 8a8a03
Packit Service 8a8a03
        pd_add_flag = report.CD_FLAG_TXT | report.CD_FLAG_ISNOTEDITABLE
Packit Service 8a8a03
Packit Service 8a8a03
        package = dump_dir.load_text(FILENAME_PACKAGE, dd_load_flag)
Packit Service 8a8a03
        if package:
Packit Service 8a8a03
            prblm_dt.add(FILENAME_PACKAGE, package, pd_add_flag)
Packit Service 8a8a03
        prblm_dt.add(CD_DUMPDIR, problem_dir, pd_add_flag)
Packit Service 8a8a03
Packit Service 8a8a03
        for element in (FILENAME_UID, FILENAME_UUID, FILENAME_DUPHASH):
Packit Service 8a8a03
            val = dump_dir.load_text(element, dd_load_flag)
Packit Service 8a8a03
            if val is not None:
Packit Service 8a8a03
                prblm_dt.add(element, val, pd_add_flag)
Packit Service 8a8a03
    finally:
Packit Service 8a8a03
        dump_dir.close()
Packit Service 8a8a03
Packit Service 8a8a03
    return prblm_dt
Packit Service 8a8a03
Packit Service 8a8a03
Packit Service 8a8a03
if __name__ == "__main__":
Packit Service 8a8a03
    CMDARGS = ArgumentParser(
Packit Service 8a8a03
            description=("Announce a new or duplicated problem via"
Packit Service 8a8a03
                " all accessible channels"),
Packit Service 8a8a03
            epilog=("Reads the default configuration from 'abrt.conf' file"))
Packit Service 8a8a03
    CMDARGS.add_argument("-d", "--problem-dir",
Packit Service 8a8a03
            type=str, required=True,
Packit Service 8a8a03
            help="An absolute path to a new or duplicated problem directory")
Packit Service 8a8a03
    CMDARGS.add_argument("-v", "--verbose",
Packit Service 8a8a03
            action="count", dest="verbose", default=0,
Packit Service 8a8a03
            help="Be verbose")
Packit Service 8a8a03
    CMDARGS.add_argument("-a", "--autoreporting",
Packit Service 8a8a03
            action="store_true", dest="autoreporting", default=False,
Packit Service 8a8a03
            help="Force to run autoreporting event")
Packit Service 8a8a03
    CMDARGS.add_argument("-e", "--autoreporting-event",
Packit Service 8a8a03
            type=str, dest="autoreporting_event",
Packit Service 8a8a03
            help="Overwrite autoreporting event name")
Packit Service 8a8a03
Packit Service 8a8a03
    OPTIONS = CMDARGS.parse_args()
Packit Service 8a8a03
Packit Service 8a8a03
    DIR_PATH = OPTIONS.problem_dir
Packit Service 8a8a03
Packit Service 8a8a03
    verbose = 0
Packit Service 8a8a03
    ABRT_VERBOSE = os.getenv("ABRT_VERBOSE")
Packit Service 8a8a03
    if ABRT_VERBOSE:
Packit Service 8a8a03
        try:
Packit Service 8a8a03
            verbose = int(ABRT_VERBOSE)
Packit Service 8a8a03
        except:
Packit Service 8a8a03
            pass
Packit Service 8a8a03
Packit Service 8a8a03
    verbose += OPTIONS.verbose
Packit Service 8a8a03
    set_verbosity(verbose)
Packit Service 8a8a03
    os.environ["ABRT_VERBOSE"] = str(verbose)
Packit Service 8a8a03
Packit Service 8a8a03
    try:
Packit Service 8a8a03
        conf = problem.load_conf_file("abrt.conf")
Packit Service 8a8a03
    except OSError as ex:
Packit Service 8a8a03
        sys.stderr.write("{0}".format(str(ex)))
Packit Service 8a8a03
        sys.exit(RETURN_FAILURE)
Packit Service 8a8a03
Packit Service 8a8a03
    try:
Packit Service 8a8a03
        PD = build_notification_problem_data(DIR_PATH)
Packit Service 8a8a03
    except ValueError as ex:
Packit Service 8a8a03
        sys.stderr.write("Cannot notify '{0}': {1}\n".
Packit Service 8a8a03
                format(DIR_PATH, str(ex)))
Packit Service 8a8a03
        sys.exit(RETURN_FAILURE)
Packit Service 8a8a03
Packit Service 8a8a03
    # The execution must continue because we should try to notify via all
Packit Service 8a8a03
    # configured channels. One of them might work properly.
Packit Service 8a8a03
    return_status = RETURN_OK
Packit Service 8a8a03
    try:
Packit Service 8a8a03
        emit_crash_dbus_signal(PD)
Packit Service 8a8a03
    except RuntimeError as ex:
Packit Service 8a8a03
        sys.stderr.write("Cannot notify '{0}' via D-Bus: {1}\n".
Packit Service 8a8a03
                format(DIR_PATH, str(ex)))
Packit Service 8a8a03
        return_status = RETURN_FAILURE
Packit Service 8a8a03
    except KeyError as ex:
Packit Service 8a8a03
        # this is a bug in build_notification_problem_data()
Packit Service 8a8a03
        sys.stderr.write("BUG: problem data misses required element '{0}'"
Packit Service 8a8a03
                         " required for D-Bus notification\n"
Packit Service 8a8a03
                         .format(str(ex)))
Packit Service 8a8a03
Packit Service 8a8a03
        return_status = RETURN_FAILURE
Packit Service 8a8a03
Packit Service 8a8a03
    if OPTIONS.autoreporting or conf.get("AutoreportingEnabled", "no") == "yes":
Packit Service 8a8a03
        event_name = OPTIONS.autoreporting_event
Packit Service 8a8a03
        if not event_name:
Packit Service 8a8a03
            if "AutoreportingEvent" in conf:
Packit Service 8a8a03
                event_name = conf["AutoreportingEvent"]
Packit Service 8a8a03
            else:
Packit Service 8a8a03
                sys.stderr.write("Autoreporting event is not configured\n")
Packit Service 8a8a03
                return_status = RETURN_FAILURE
Packit Service 8a8a03
Packit Service 8a8a03
        if event_name:
Packit Service 8a8a03
            try:
Packit Service 8a8a03
                run_autoreport(PD, event_name)
Packit Service 8a8a03
            except RuntimeError as ex:
Packit Service 8a8a03
                sys.stderr.write("Cannot notify '{0}' via uReport: {1}\n".
Packit Service 8a8a03
                        format(DIR_PATH, str(ex)))
Packit Service 8a8a03
                return_status = RETURN_FAILURE
Packit Service 8a8a03
            except KeyError as ex:
Packit Service 8a8a03
                # this is a bug in build_notification_problem_data()
Packit Service 8a8a03
                sys.stderr.write(
Packit Service 8a8a03
                    "BUG: problem data misses required element '{0}'"
Packit Service 8a8a03
                    " required for uReport notification\n".format(str(ex)))
Packit Service 8a8a03
Packit Service 8a8a03
                return_status = RETURN_FAILURE
Packit Service 8a8a03
Packit Service 8a8a03
    # log problem to systemd journal with SYSLOG_IDENTIFIER=abrt-notification
Packit Service 8a8a03
    os.environ["REPORTER_JOURNAL_SYSLOG_ID"] = "abrt-notification"
Packit Service 8a8a03
    if not run_event("report_systemd-journal", DIR_PATH):
Packit Service 8a8a03
        # if report_systemd-journal is not defined, run 'reporter-systemd-journald'
Packit Service 8a8a03
        try:
Packit Service 8a8a03
            call(["reporter-systemd-journald", "-d " + DIR_PATH])
Packit Service 8a8a03
        except FileNotFoundError as ex:
Packit Service 8a8a03
            # we expect the reporter doesn't have to be installed
Packit Service 8a8a03
            log1("reporter-systemd-journald was not found")
Packit Service 8a8a03
Packit Service 8a8a03
    sys.exit(return_status)
Packit Service 8a8a03