Example #1
0
 def test_publish_to_config_exchange(self):
     """Assert a message can be published to the exchange form config."""
     message = "test_message"
     expected_pre_publish_signal_data = {
         "called": True,
         "sender": api.publish,
         "args": {"message": message},
     }
     expected_publish_signal_data = {
         "called": True,
         "sender": api.publish,
         "args": {"message": message},
     }
     expected_publish_failed_signal_data = {
         "called": False,
         "sender": None,
         "args": None,
     }
     api.publish(message)
     self.mock_publisher_session.assert_called_once_with()
     self.mock_publisher_session.publish.assert_called_once_with(
         message, exchange="test_publich_exchange"
     )
     self.assertEqual(self.pre_publish_signal_data, expected_pre_publish_signal_data)
     self.assertEqual(self.publish_signal_data, expected_publish_signal_data)
     self.assertEqual(
         self.publish_failed_signal_data, expected_publish_failed_signal_data
     )
def test_twisted_consume_update_callback():
    """Assert a second call to consume updates an existing callback."""
    queue = str(uuid.uuid4())
    queues = {queue: {"auto_delete": False, "arguments": {"x-expires": 60 * 1000}}}
    bindings = [{"queue": queue, "exchange": "amq.topic", "routing_keys": ["#"]}]

    callback1 = defer.Deferred()
    callback2 = defer.Deferred()

    consumers1 = yield api.twisted_consume(
        lambda m: reactor.callFromThread(callback1.callback, m), bindings, queues
    )
    api.publish(message.Message(), "amq.topic")
    _add_timeout(callback1, 10)
    try:
        yield callback1
    except (defer.TimeoutError, defer.CancelledError):
        pytest.fail("Never received message for initial callback")

    consumers2 = yield api.twisted_consume(
        lambda m: reactor.callFromThread(callback2.callback, m), bindings, queues
    )
    api.publish(message.Message(), "amq.topic")
    _add_timeout(callback2, 10)
    try:
        yield callback2
    except (defer.TimeoutError, defer.CancelledError):
        pytest.fail("Never received message for updated callback")

    assert consumers1[0]._tag == consumers2[0]._tag

    yield consumers2[0].cancel()
Example #3
0
def fedmsg_publish(*args, **kwargs):  # pragma: no cover
    """ Try to publish a message on the fedmsg bus. """
    if config.config["LEGACY_MESSAGING"]:
        # We catch Exception if we want :-p
        # pylint: disable=W0703
        # Ignore message about fedmsg import
        # pylint: disable=F0401
        kwargs["modname"] = "anitya"
        kwargs["cert_prefix"] = "anitya"
        kwargs["name"] = "relay_inbound"
        kwargs["active"] = True
        try:
            import fedmsg

            fedmsg.publish(*args, **kwargs)
        except Exception as err:
            _log.error(str(err))
    else:
        try:
            message_class = message.get_class("anitya." + kwargs["topic"])
            api.publish(
                message_class(
                    topic="anitya.{}".format(kwargs["topic"]), body=kwargs["msg"]
                )
            )
        except (
            fm_exceptions.ConnectionException,
            fm_exceptions.PublishException,
        ) as err:
            # For now, continue just logging the error. Once the messaging has
            # been untangled into SQLAlchemy events, it should probably result
            # in an exception and the client should try again later.
            _log.error(str(err))
Example #4
0
    def test_publish_to_exchange(self, mock_twisted_publish):
        """Assert a message can be published to the exchange."""
        message = "test_message"
        exchange = "test_exchange"
        expected_pre_publish_signal_data = {
            "called": True,
            "sender": api.publish,
            "args": {"message": message},
        }
        expected_publish_signal_data = {
            "called": True,
            "sender": api.publish,
            "args": {"message": message},
        }
        expected_publish_failed_signal_data = {
            "called": False,
            "sender": None,
            "args": None,
        }

        api.publish(message, exchange)

        mock_twisted_publish.assert_called_once_with(message, exchange)
        mock_twisted_publish.return_value.wait.assert_called_once_with(timeout=30)
        self.assertEqual(self.pre_publish_signal_data, expected_pre_publish_signal_data)
        self.assertEqual(self.publish_signal_data, expected_publish_signal_data)
        self.assertEqual(
            self.publish_failed_signal_data, expected_publish_failed_signal_data
        )
def test_twisted_consume_halt_consumer_requeue():
    """Assert raising HaltConsumer with requeue=True re-queues the message."""
    queue = str(uuid.uuid4())
    queues = {queue: {"auto_delete": False, "arguments": {"x-expires": 60 * 1000}}}
    bindings = [{"queue": queue, "exchange": "amq.topic", "routing_keys": ["#"]}]
    msg = message.Message(
        topic=u"nice.message",
        headers={u"niceness": u"very"},
        body={u"encouragement": u"You're doing great!"},
    )

    def callback(message):
        """Count to 3 and quit."""
        raise exceptions.HaltConsumer(exit_code=1, requeue=True)

    # Assert that the number of consumers we think we started is the number the
    # server things we started. This will fail if other tests don't clean up properly.
    # If it becomes problematic perhaps each test should have a vhost.
    consumers = yield api.twisted_consume(callback, bindings, queues)
    api.publish(msg, "amq.topic")

    _add_timeout(consumers[0].result, 10)
    try:
        yield consumers[0].result
    except exceptions.HaltConsumer as e:
        # Assert there are no consumers for the queue, and that there's a ready message
        assert e.exit_code == 1

        server_queue = yield get_queue(queue)
        assert server_queue["consumers"] == 0
        assert server_queue["messages_ready"] == 1
    except (defer.TimeoutError, defer.CancelledError):
        yield consumers[0].cancel()
        pytest.fail("Timeout reached without consumer halting!")
    def test_pub_sub_default_settings(self):
        """
        Assert publishing and subscribing works with the default configuration.

        This should work because the publisher uses the 'amq.topic' exchange by
        default and the consumer also uses the 'amq.topic' exchange with its
        auto-named queue and a default subscription key of '#'.
        """

        # Consumer setup
        def counting_callback(message, storage=defaultdict(int)):
            storage[message.topic] += 1
            if storage[message.topic] == 3:
                raise exceptions.HaltConsumer()

        consumer_process = multiprocessing.Process(
            target=api.consume, args=(counting_callback,))
        msg = message.Message(topic=u'nice.message', headers={u'niceness': u'very'},
                              body={u'encouragement': u"You're doing great!"})

        consumer_process.start()
        # Allow the consumer time to create the queues and bindings
        time.sleep(5)

        for _ in range(0, 3):
            api.publish(msg)

        consumer_process.join(timeout=30)
        self.assertEqual(0, consumer_process.exitcode)
Example #7
0
 def test_session_cache_has_session(self):
     """Assert a TLS vaiable _session_cache contains 'session'."""
     message = "test_message"
     exchange = "test_exchange"
     expected_pre_publish_signal_data = {
         "called": True,
         "sender": api.publish,
         "args": {"message": message},
     }
     expected_publish_signal_data = {
         "called": True,
         "sender": api.publish,
         "args": {"message": message},
     }
     expected_publish_failed_signal_data = {
         "called": False,
         "sender": None,
         "args": None,
     }
     self.mock_session_cache.session = self.mock_publisher_session
     api.publish(message, exchange)
     self.mock_publisher_session.assert_not_called()
     self.mock_publisher_session.publish.assert_called_once_with(
         message, exchange=exchange
     )
     self.assertEqual(self.pre_publish_signal_data, expected_pre_publish_signal_data)
     self.assertEqual(self.publish_signal_data, expected_publish_signal_data)
     self.assertEqual(
         self.publish_failed_signal_data, expected_publish_failed_signal_data
     )
Example #8
0
def fedmsg_publish(*args, **kwargs):  # pragma: no cover
    """ Try to publish a message on the fedmsg bus. """
    if config.config["LEGACY_MESSAGING"]:
        # We catch Exception if we want :-p
        # pylint: disable=W0703
        # Ignore message about fedmsg import
        # pylint: disable=F0401
        kwargs["modname"] = "anitya"
        kwargs["cert_prefix"] = "anitya"
        kwargs["name"] = "relay_inbound"
        kwargs["active"] = True
        try:
            import fedmsg

            fedmsg.publish(*args, **kwargs)
        except Exception as err:
            _log.error(str(err))
    else:
        try:
            message_class = message.get_class("anitya." + kwargs["topic"])
            api.publish(
                message_class(
                    topic="anitya.{}".format(kwargs["topic"]), body=kwargs["msg"]
                )
            )
        except (
            fm_exceptions.ConnectionException,
            fm_exceptions.PublishException,
        ) as err:
            # For now, continue just logging the error. Once the messaging has
            # been untangled into SQLAlchemy events, it should probably result
            # in an exception and the client should try again later.
            _log.error(str(err))
Example #9
0
def publish_message(topic,
                    project=None,
                    distro=None,
                    message=None):  # pragma: no cover
    """Try to publish a message.

    Args:
        topic (str): Topic of the message
        project (dict): Dictionary representing project
        distro (str): Name of the distribution
        message (dict): Additional data needed for the topic
    """

    msg = dict(project=project, distro=distro, message=message)
    try:
        message_class = fm_message.get_class("anitya." + topic)
        api.publish(message_class(topic="anitya.{}".format(topic), body=msg))
    except (
            fm_exceptions.ConnectionException,
            fm_exceptions.PublishException,
    ) as err:
        # For now, continue just logging the error. Once the messaging has
        # been untangled into SQLAlchemy events, it should probably result
        # in an exception and the client should try again later.
        _log.error(str(err))
Example #10
0
    def v2_playbook_on_play_start(self, play):
        # This gets called once for each play.. but we just issue a message once
        # for the first one.  One per "playbook"
        if self.playbook:
            # figure out where the playbook FILE is
            path = os.path.abspath(self.playbook._file_name)

            # Bail out early without publishing if we're in --check mode
            if self.play_context.check_mode:
                return

            if not self.playbook_path:
                try:
                    msg = Message(
                        topic="ansible.playbook.start",
                        body={
                            'playbook': path,
                            'userid': getlogin(),
                            'extra_vars': play._variable_manager.extra_vars,
                            'inventory':
                            play._variable_manager._inventory._sources,
                            'playbook_checksum': secure_hash(path),
                            'check': self.play_context.check_mode
                        })
                    publish(msg)
                except PublishReturned as e:
                    LOGGER.warning(
                        "Fedora Messaging broker rejected message %s: %s",
                        msg.id, e)
                except ConnectionException as e:
                    LOGGER.warning("Error sending message %s: %s", msg.id, e)
                self.playbook_path = path
Example #11
0
def admin_new_release():
    if not is_admin():
        flask.flash("You are not an admin", "error")
        return flask.redirect(flask.url_for("ui.index"))

    form = forms.ReleaseForm()
    if form.validate_on_submit():
        release = db.Release()
        form.populate_obj(obj=release)
        db.Session.add(release)
        db.Session.commit()

        message = fm_api.Message(
            topic="kerneltest.release.new",
            body={
                "agent": flask.g.user.username,
                "release": {
                    "releasenum": release.version,
                    "support": release.support
                },
            },
        )
        try:
            fm_api.publish(message)
        except (
                fm_api.exceptions.ConnectionException,
                fm_api.exceptions.ConnectionException,
        ):
            pass

        flask.flash('Release "%s" added' % release.version)
        return flask.redirect(flask.url_for("ui.index"))
    return flask.render_template("release_new.html",
                                 form=form,
                                 submit_text="Create release")
Example #12
0
def publish(topic, msg, force=False):
    """
    Send a message via Fedora Messaging.

    This is used to send a message to the AMQP broker.

    Args:
        topic (str): The topic suffix. The "bodhi" prefix is applied (along with
            the "topic_prefix" settings from Fedora Messaging).
        msg (dict): The message body to send.
        force (bool): If False (the default), the message is only sent after the
            currently active database transaction successfully commits. If true,
            the messages is sent immediately.
    """
    # Dirty, nasty hack that I feel shame for: use the fedmsg encoder that modifies
    # messages quietly if they have objects with __json__ methods on them.
    # For now, copy that behavior. In the future, callers should pass
    # fedora_messaging.api.Message sub-classes or this whole API should go away.
    body = json.loads(json.dumps(msg, cls=FedMsgEncoder))

    message = api.Message(topic="bodhi.{}".format(topic), body=body)
    if force:
        api.publish(message)
        return

    session = Session()
    if 'messages' not in session.info:
        session.info['messages'] = []
    session.info['messages'].append(message)
    _log.debug('Queuing message %r for delivery on session commit', message.id)
Example #13
0
def test_consume_halt_with_exitcode(callback, exit_code, msg, queue):
    """Assert user execution halt with reason and exit_code is reported."""
    args = [
        "fedora-messaging",
        "--conf={}".format(CLI_CONF),
        "consume",
        "--callback=fedora_messaging.tests.integration.test_cli:{}".format(
            callback),
        "--queue-name={}".format(queue),
        "--exchange=amq.topic",
        "--routing-key=#",
    ]

    process = subprocess.Popen(args,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.PIPE)
    time.sleep(5)

    api.publish(message.Message())
    for _ in range(5):
        time.sleep(1)
        if process.poll() is not None:
            break
    else:
        process.kill()
        pytest.fail("Process never stopped!: {}".format(process.stdout.read()))

    assert process.returncode == exit_code
    assert msg in process.stdout.read()
Example #14
0
def _publish_with_retry(message: 'base.BodhiMessage'):
    """
    Call fedora_messaging.api.publish with the given message, and retry upon temporary failures.

    The goal of this function is to try to recover from temporary failures by trying again for a
    while. If it is unable to succeed, it will ultimately raise the Exception.
    """
    api.publish(message)
Example #15
0
def fedora_messaging_change(change_id):
    change = Change.objects.get(pk=change_id)
    publish(
        Message(
            topic=get_change_topic(change),
            headers=get_change_headers(change),
            body=get_change_body(change),
        ))
Example #16
0
def test_twisted_consume_drop_message():
    """Assert raising Drop causes the message to be dropped, but processing continues."""
    queue = str(uuid.uuid4())
    queues = {
        queue: {
            "auto_delete": False,
            "arguments": {
                "x-expires": 60 * 1000
            }
        }
    }
    bindings = [{
        "queue": queue,
        "exchange": "amq.topic",
        "routing_keys": ["#"]
    }]
    msg = message.Message(
        topic=u"nice.message",
        headers={u"niceness": u"very"},
        body={u"encouragement": u"You're doing great!"},
    )
    dropped_messages = []

    def callback(message):
        """Drop 1 message and then halt on the second message."""
        dropped_messages.append(message)
        if len(dropped_messages) == 2:
            raise exceptions.HaltConsumer()
        raise exceptions.Drop()

    # Assert that the number of consumers we think we started is the number the
    # server things we started. This will fail if other tests don't clean up properly.
    # If it becomes problematic perhaps each test should have a vhost.
    consumers = yield api.twisted_consume(callback, bindings, queues)
    api.publish(msg, "amq.topic")
    api.publish(msg, "amq.topic")

    _add_timeout(consumers[0].result, 10)
    try:
        yield consumers[0].result
    except exceptions.HaltConsumer:
        # Assert both messages are delivered, no messages are un-acked, and only one
        # message got a positive acknowledgment.
        server_queue = yield task.deferLater(
            reactor,
            5,
            treq.get,
            HTTP_API + "queues/%2F/" + queue,
            auth=HTTP_AUTH,
            timeout=3,
        )
        server_queue = yield server_queue.json()
        assert server_queue["consumers"] == 0
        assert server_queue["messages"] == 0
    except (defer.TimeoutError, defer.CancelledError):
        pytest.fail("Timeout reached without consumer halting!")
    finally:
        yield consumers[0].cancel()
Example #17
0
def publish_fedmsg(session, message):
    if not get_config('fedmsg-publisher.enabled', False):
        return
    message = fedmsg.Message(
        topic='{modname}.{topic}'.format(**message),
        body=message['msg'],
    )
    session.log.info('Publishing fedmsg:\n' + str(message))
    fedmsg.publish(message)
Example #18
0
def test_twisted_consume_general_exception():
    """
    Assert if the callback raises an unhandled exception, it is passed on to the
    consumer.result and the message is re-queued.
    """
    queue = str(uuid.uuid4())
    queues = {
        queue: {
            "auto_delete": False,
            "arguments": {
                "x-expires": 60 * 1000
            }
        }
    }
    bindings = [{
        "queue": queue,
        "exchange": "amq.topic",
        "routing_keys": ["#"]
    }]
    msg = message.Message(
        topic=u"nice.message",
        headers={u"niceness": u"very"},
        body={u"encouragement": u"You're doing great!"},
    )

    def callback(message):
        """An *exceptionally* useless callback"""
        raise Exception("Oh the huge manatee")

    # Assert that the number of consumers we think we started is the number the
    # server things we started. This will fail if other tests don't clean up properly.
    # If it becomes problematic perhaps each test should have a vhost.
    consumers = yield api.twisted_consume(callback, bindings, queues)
    api.publish(msg, "amq.topic")

    _add_timeout(consumers[0].result, 10)
    try:
        yield consumers[0].result
        pytest.fail("Expected an exception to be raised.")
    except (defer.TimeoutError, defer.CancelledError):
        pytest.fail("Timeout reached without consumer halting!")
    except Exception as e:
        # Assert the message was delivered and re-queued when the consumer crashed.
        assert e.args[0] == "Oh the huge manatee"
        server_queue = yield task.deferLater(
            reactor,
            10,
            treq.get,
            HTTP_API + "queues/%2F/" + queue,
            auth=HTTP_AUTH,
            timeout=3,
        )
        server_queue = yield server_queue.json()
        assert server_queue["consumers"] == 0
        assert server_queue["messages"] == 1
    finally:
        yield consumers[0].cancel()
Example #19
0
def _do_publish(session, topic, body):
    namespace = get_config('osci.namespace')
    artifact_type = get_config('osci.build_group_artifact_type')
    message = fedmsg.Message(
        topic=f'ci.{namespace}.{artifact_type}.test.{topic}',
        body=body,
    )
    session.log.info('Publishing fedmsg:\n' + str(message))
    fedmsg.publish(message)
def publish(message):
    """
    Publish message through fedora-messaging.

    Params:
        message (dict): JSON representation of the message
    """
    msg = fm_message.Message(topic=message["topic"], body=message["msg"])

    api.publish(msg)
def publish(message):
    """
    Publish message through fedora-messaging.

    Params:
        message (dict): JSON representation of the message
    """
    msg = fm_message.Message(topic=message["topic"], body=message["msg"])

    api.publish(msg)
def _fedora_messaging_publish(topic, msg):
    from fedora_messaging import api, message

    if conf.dry_run:
        logger.info(
            'DRY-RUN: send message to fedora-messaging, topic: %s, msg: %s',
            topic, msg)
    else:
        fm_msg = message.Message(topic=topic, body=msg)
        logger.debug('Send message: %s', fm_msg)
        api.publish(fm_msg)
    def publish(self, message):

        try:
            msg = Message(topic='{}.result.new'.format(self.modname),
                          body=message)
            publish(msg)
        except PublishReturned as e:
            log.error('Fedora Messaging broker rejected message {}: {}'.format(
                msg.id, e))
        except ConnectionException as e:
            log.error('Error sending message {}: {}'.format(msg.id, e))
    def notify(self, package: Package, message: str, opts: dict) -> dict:
        """
        This method is inherited from `hotness.notifiers.Notifier`.

        It publishes messages to Fedora messaging broker.

        Params:
            package: Package to create notification for
            message: Topic for the message
            opts: Additional options for fedora message. Example:
                {
                    "body": {} # Body of the message we want to sent. Look at the
                               # hotness_schema for more info
                }

        Returns:
            Dictionary containing message id
            Example:
            {
                "msg_id": "ae68f"
            }

        Raises:
            NotifierException: When the required `opts` parameters are missing or
                               error happens during publishing.
        """
        topic = self.prefix + "." + message
        body = opts.get("body", {})
        output = {}

        if not body:
            raise NotifierException(
                "Additional parameters are missing! Please provide `body` for the message."
            )

        message_class = fm_message.get_class(topic)
        if not message_class:
            raise NotifierException("Unknown topic provided '{}'".format(topic))

        _logger.info("publishing topic %r" % topic)
        try:
            msg = message_class(topic=topic, body=body)
            api.publish(msg)
        except PublishException as e:
            raise NotifierException(
                "Fedora messaging broker rejected message {}:{}".format(msg.id, e)
            )
        except ConnectionException as e:
            raise NotifierException("Error sending the message {}:{}".format(msg.id, e))
        finally:
            output["msg_id"] = msg.id

        return output
def test_twisted_consume_halt_consumer():
    """
    Assert raising HaltConsumer works with :func:`fedora_messaging.api.twisted_consume`
    API.
    """
    queue = str(uuid.uuid4())
    queues = {queue: {"auto_delete": False, "arguments": {"x-expires": 60 * 1000}}}
    bindings = [{"queue": queue, "exchange": "amq.topic", "routing_keys": ["#"]}]
    msg = message.Message(
        topic=u"nice.message",
        headers={u"niceness": u"very"},
        body={u"encouragement": u"You're doing great!"},
    )
    expected_headers = {
        u"fedora_messaging_severity": 20,
        u"fedora_messaging_schema": u"base.message",
        u"niceness": u"very",
    }
    messages_received = []

    def callback(message):
        """Count to 3 and quit."""
        messages_received.append(message)
        if len(messages_received) == 3:
            raise exceptions.HaltConsumer()

    consumers = yield api.twisted_consume(callback, bindings, queues)

    # Assert the server reports a consumer
    server_queue = yield get_queue(queue)
    assert server_queue["consumers"] == 1

    for _ in range(0, 3):
        api.publish(msg, "amq.topic")

    _add_timeout(consumers[0].result, 10)
    try:
        yield consumers[0].result
    except exceptions.HaltConsumer as e:
        assert len(messages_received) == 3
        assert e.exit_code == 0
        for m in messages_received:
            assert u"nice.message" == m.topic
            assert {u"encouragement": u"You're doing great!"} == m.body
            assert "sent-at" in m._headers
            del m._headers["sent-at"]
            assert expected_headers == m._headers
        server_queue = yield get_queue(queue)
        assert server_queue["consumers"] == 0
    except (defer.TimeoutError, defer.CancelledError):
        yield consumers[0].cancel()
        pytest.fail("Timeout reached without consumer halting!")
def publish_taskotron_message(result, include_job_url=False):
    """
    Publish a fedmsg on the taskotron topic with Taskotron-compatible structure.

    These messages are deprecated, consumers should consume from the resultsdb
    topic instead.
    """
    prev_result = get_prev_result(result)
    if prev_result is not None and prev_result.outcome == result.outcome:
        # If the previous result had the same outcome, skip publishing
        # a message for this new result.
        # This was intended as a workaround to avoid spammy messages from the
        # dist.depcheck task, which tends to produce a very large number of
        # identical results for any given build, because of the way that it is
        # designed.
        log.debug(
            "Skipping Taskotron message for result %d, outcome has not changed",
            result.id)
        return

    task = dict((datum.key, datum.value) for datum in result.data
                if datum.key in (
                    'item',
                    'type',
                ))
    task['name'] = result.testcase.name
    body = {
        'task': task,
        'result': {
            'id': result.id,
            'submit_time':
            result.submit_time.strftime("%Y-%m-%d %H:%M:%S UTC"),
            'prev_outcome': prev_result.outcome if prev_result else None,
            'outcome': result.outcome,
            'log_url': result.ref_url,
        }
    }

    if include_job_url:  # only in the v1 API
        body['result'][
            'job_url'] = result.groups[0].ref_url if result.groups else None

    try:
        msg = Message(topic='taskotron.result.new', body=body)
        publish(msg)
    except PublishReturned as e:
        log.error('Fedora Messaging broker rejected message {}: {}'.format(
            msg.id, e))
    except ConnectionException as e:
        log.error('Error sending message {}: {}'.format(msg.id, e))
Example #27
0
def test_twisted_stop_service():
    """
    Assert stopping the service, which happens when the reactor shuts down, waits
    for consumers to finish processing and then cancels them before closing the connection.
    """
    queue = str(uuid.uuid4())
    queues = {
        queue: {
            "auto_delete": False,
            "arguments": {
                "x-expires": 60 * 1000
            }
        }
    }
    bindings = [{
        "queue": queue,
        "exchange": "amq.topic",
        "routing_keys": ["#"]
    }]
    message_received, message_processed = defer.Deferred(), defer.Deferred()

    def callback(message):
        """Callback when the message is received, introduce a delay, then callback again."""
        reactor.callFromThread(message_received.callback, None)
        time.sleep(5)
        reactor.callFromThread(message_processed.callback, None)

    consumers = yield api.twisted_consume(callback, bindings, queues)
    api.publish(message.Message(), "amq.topic")

    _add_timeout(consumers[0].result, 10)
    _add_timeout(message_received, 10)
    try:
        yield message_received
    except (defer.TimeoutError, defer.CancelledError):
        yield consumers[0].cancel()
        pytest.fail("Timeout reached without consumer receiving message!")

    assert not message_processed.called
    deferred_stop = api._twisted_service.stopService()

    _add_timeout(message_processed, 10)
    try:
        yield message_processed
        # The request to stop should wait on the message to be processed
        assert deferred_stop.called is False
    except (defer.TimeoutError, defer.CancelledError):
        pytest.fail("Timeout reached without consumer processing message")
    yield deferred_stop
Example #28
0
def send_messages_after_commit(session):
    """
    Send messages via AMQP after a database commit occurs.

    Args:
        session (sqlalchemy.orm.session.Session): The session that was committed.
    """
    if 'messages' in session.info:
        for m in session.info['messages']:
            try:
                api.publish(m)
            except fml_exceptions.BaseException:
                # In the future we should handle errors more gracefully
                _log.exception("An error occurred publishing %r after a database commit", m)
        session.info['messages'] = []
Example #29
0
    def v2_playbook_on_stats(self, stats):
        if not self.playbook_path:
            return

        results = dict([(h, stats.summarize(h)) for h in stats.processed])
        try:
            msg = Message(topic="ansible.playbook.complete",
                          body={
                              'playbook': self.playbook_path,
                              'userid': getlogin(),
                              'results': results
                          })
            publish(msg)
        except PublishReturned as e:
            LOGGER.warning("Fedora Messaging broker rejected message %s: %s",
                           msg.id, e)
        except ConnectionException as e:
            LOGGER.warning("Error sending message %s: %s", msg.id, e)
Example #30
0
def enqueue(data, topic, headers):
    DQ.append((data, topic, headers))

    while DQ:
        _data, _topic, _headers = DQ.popleft()
        try:
            if get_bool_env('IS_PRODUCTION', DEFAULT_IS_PRODUCTION):
                msg = message.Message(topic=_topic,
                                      headers=_headers,
                                      body=_data)
                api.publish(msg)
                app.logger.info(f'Sending payload to {_topic}')
            else:
                app.logger.info(f'\n---\n{_topic}\n{_headers}\n{_data}\n---')
        except Exception:
            app.logger.exception(
                'Error during sending message, will be retried')
            DQ.appendleft((_data, _topic, _headers))
Example #31
0
def admin_edit_release(relnum):
    if not is_admin():
        flask.flash("You are not an admin", "error")
        return flask.redirect(flask.url_for("ui.index"))

    release = db.Release.query.filter_by(version=relnum).one_or_none()
    if not release:
        flask.flash("No release %s found" % relnum)
        return flask.redirect(flask.url_for("ui.index"))

    form = forms.ReleaseForm(obj=release)
    if form.validate_on_submit():
        form.populate_obj(obj=release)
        db.Session.commit()

        message = fm_api.Message(
            topic="kerneltest.release.edit",
            body={
                "agent": flask.g.user.username,
                "release": {
                    "releasenum": release.version,
                    "support": release.support
                },
            },
        )
        try:
            fm_api.publish(message)
        except (
                fm_api.exceptions.ConnectionException,
                fm_api.exceptions.ConnectionException,
        ):
            pass

        flask.flash('Release "%s" updated' % release.version)
        return flask.redirect(flask.url_for("ui.index"))
    return flask.render_template("release_new.html",
                                 form=form,
                                 release=release,
                                 submit_text="Edit release")
Example #32
0
    def get(self, request, *args, **kwargs):
        try:
            message = Message.objects.get(identifier=kwargs['identifier'], sender_email_token=kwargs['token'])
        except Message.DoesNotExist:
            response = render(request, self.template_name, {'not_found': True})
            response.status_code = 404
            return response
 
        if message.sender_email != self.request.user.email:
            response = render(request, self.template_name, {'not_sender': True})
            response.status_code = 400
            return response
        if message.status != Message.STATUS.pending_sender_confirmation:
            response = render(request, self.template_name, {'already_confirmed': True})
            return response
        message.send_to_recipient(self.request.is_secure(), self.request.get_host())

        sender_name = self.request.user.username if message.sender_named else "Anonymous"
        recipient_name = message.recipient_username if message.recipient_username else message.recipient_name
        message = MessageV1(
            topic="happinesspacket.send",
            body={
                "id": message.identifier,
                "sender": sender_name,
                "recipient": recipient_name
            }
        )
        try:
            publish(message)
        except PublishReturned:
            response = render(request, self.template_name, {'publish_returned': True})
            response.status_code = 500
            return response
        except ConnectionException:
            response = render(request, self.template_name, {'connection_exception': True})
            response.status_code = 500
            return response
        return HttpResponseRedirect(reverse('messaging:sender_confirmed'))
Example #33
0
    def run(self, cmdline, db):
        levels = tuple(10**n for n in range(7))
        if cmdline.reports:
            # Sum of counts until yesterday
            q_yesterday = (
                db.session
                .query(Report.id.label("y_report_id"),
                       func.sum(ReportHistoryDaily.count).label("sum_yesterday"))
                .outerjoin(ReportHistoryDaily)
                .filter(ReportHistoryDaily.day < cmdline.date)
                .group_by(Report.id)
                .subquery()
                )
            # Sum of counts until today
            q_today = (
                db.session
                .query(Report.id.label("t_report_id"),
                       func.sum(ReportHistoryDaily.count).label("sum_today"))
                .outerjoin(ReportHistoryDaily)
                .filter(ReportHistoryDaily.day <= cmdline.date)
                .group_by(Report.id)
                .subquery()
                )
            q = (db.session.query(Report,
                                  q_today.c.sum_today,
                                  q_yesterday.c.sum_yesterday)
                 .outerjoin(q_today, Report.id == q_today.c.t_report_id)
                 .outerjoin(q_yesterday, Report.id == q_yesterday.c.y_report_id)
                 .filter(or_(Report.max_certainty.isnot(None), Report.max_certainty != 100))
                 .filter(or_(and_(q_yesterday.c.sum_yesterday.is_(None),
                                  q_today.c.sum_today.isnot(None)),
                             q_today.c.sum_today != q_yesterday.c.sum_yesterday))
                )

            for db_report, sum_today, sum_yesterday in q.yield_per(100):
                # avoid None
                sum_yesterday = sum_yesterday or 0

                for level in levels:
                    if sum_yesterday < level <= sum_today:
                        self.log_info("Notifying about report #{0} level {1}"
                                      .format(db_report.id, level))
                        msg_body = {
                            "report_id": db_report.id,
                            "function": db_report.crash_function,
                            "components": [db_report.component.name],
                            "first_occurrence": db_report.first_occurrence
                                                .strftime("%Y-%m-%d"),
                            "count": sum_today,
                            "type": db_report.type,
                            "level": level,
                        }
                        if web.webfaf_installed():
                            msg_body["url"] = web.reverse("reports.item",
                                                          report_id=db_report.id)

                        if db_report.problem_id:
                            msg_body["problem_id"] = db_report.problem_id

                        try:
                            msg = FafReportMessage(topic="faf.report.threshold{0}".format(level),
                                                   body=msg_body)
                            publish(msg)
                        except PublishReturned as e:
                            self.log_warn("Fedora Messaging broker rejected message {0}: {1}".format(msg.id, e))
                        except ConnectionException as e:
                            self.log_warn("Error sending message {0}: {1}".format(msg.id, e))

        if cmdline.problems:
            # Sum of counts until yesterday
            q_yesterday = (
                db.session
                .query(Problem.id.label("y_problem_id"),
                       func.sum(ReportHistoryDaily.count).label("sum_yesterday"))
                .join(Report, Report.problem_id == Problem.id)
                .outerjoin(ReportHistoryDaily)
                .filter(ReportHistoryDaily.day < cmdline.date)
                .group_by(Problem.id)
                .subquery()
                )
            # Sum of counts until today
            q_today = (
                db.session
                .query(Problem.id.label("t_problem_id"),
                       func.sum(ReportHistoryDaily.count).label("sum_today"))
                .join(Report, Report.problem_id == Problem.id)
                .outerjoin(ReportHistoryDaily)
                .filter(ReportHistoryDaily.day <= cmdline.date)
                .group_by(Problem.id)
                .subquery()
                )
            q = (db.session
                 .query(Problem, q_today.c.sum_today, q_yesterday.c.sum_yesterday)
                 .outerjoin(q_today, Problem.id == q_today.c.t_problem_id)
                 .outerjoin(q_yesterday, Problem.id == q_yesterday.c.y_problem_id)
                 .filter(or_(and_(q_yesterday.c.sum_yesterday.is_(None),
                                  q_today.c.sum_today.isnot(None)),
                             q_today.c.sum_today != q_yesterday.c.sum_yesterday))
                )

            for db_problem, sum_today, sum_yesterday in q.yield_per(100):
                # avoid None
                sum_yesterday = sum_yesterday or 0

                for level in levels:
                    if sum_yesterday < level <= sum_today:
                        self.log_info("Notifying about problem #{0} level {1}"
                                      .format(db_problem.id, level))
                        msg_body = {
                            "problem_id": db_problem.id,
                            "function": db_problem.crash_function,
                            "components": list(db_problem.unique_component_names),
                            "first_occurrence": db_problem.first_occurrence
                                                .strftime("%Y-%m-%d"),
                            "count": sum_today,
                            "type": db_problem.type,
                            "level": level,
                        }
                        if web.webfaf_installed():
                            msg_body["url"] = web.reverse("problems.item",
                                                          problem_id=db_problem.id)

                        try:
                            msg = FafProblemMessage(topic="faf.problem.threshold{0}".format(level),
                                                    body=msg_body)
                            publish(msg)
                        except PublishReturned as e:
                            self.log_warn("Fedora Messaging broker rejected message {0}: {1}".format(msg.id, e))
                        except ConnectionException as e:
                            self.log_warn("Error sending message {0}: {1}".format(msg.id, e))
Example #34
0
    def fedmsg_report(target, value, oldvalue, initiator): # pylint: disable=unused-argument
        """
        Send Fedora Messaging notifications when Report.count reaches specified threshold.
        """
        try:
            db_report = target
            if notify_reports:
                oldcount = oldvalue
                newcount = value
                for level in levels:
                    if oldcount < level <= newcount:
                        logger.info("Notifying about report #{0} level {1}"
                                    .format(db_report.id, level))
                        msg_body = {
                            "report_id": db_report.id,
                            "function": db_report.crash_function,
                            "components": [db_report.component.name],
                            "first_occurrence": db_report.first_occurrence
                                                .strftime("%Y-%m-%d"),
                            "count": newcount,
                            "type": db_report.type,
                            "level": level,
                        }
                        if web.webfaf_installed() and db_report.hashes:
                            msg_body["url"] = web.reverse("reports.bthash_forward",
                                                          bthash=db_report.hashes[0].hash)

                        if db_report.problem_id:
                            msg_body["problem_id"] = db_report.problem_id

                        try:
                            msg = FafReportMessage(topic="faf.report.threshold{0}".format(level),
                                                   body=msg_body)
                            publish(msg)
                        except PublishReturned as e:
                            logger.exception("Fedora Messaging broker rejected message {0}: {1}".format(msg.id, e))
                        except ConnectionException as e:
                            logger.exception("Error sending message {0}: {1}".format(msg.id, e))

            if notify_problems and db_report.problem is not None:
                oldcount = db_report.problem.reports_count
                newcount = oldcount + value - oldvalue
                for level in levels:
                    if oldcount < level <= newcount:
                        logger.info("Notifying about problem #{0} level {1}"
                                    .format(db_report.problem.id, level))
                        msg_body = {
                            "problem_id": db_report.problem.id,
                            "function": db_report.problem.crash_function,
                            "components": list(db_report.problem.unique_component_names),
                            "first_occurrence": db_report.problem.first_occurrence
                                                .strftime("%Y-%m-%d"),
                            "count": newcount,
                            "type": db_report.type,
                            "level": level,
                        }
                        if web.webfaf_installed():
                            msg_body["url"] = web.reverse("problems.item", problem_id=db_report.problem.id)

                        try:
                            msg = FafProblemMessage(topic="faf.problem.threshold{0}".format(level),
                                                    body=msg_body)
                            publish(msg)
                        except PublishReturned as e:
                            logger.exception("Fedora Messaging broker rejected message {0}: {1}".format(msg.id, e))
                        except ConnectionException as e:
                            logger.exception("Error sending message {0}: {1}".format(msg.id, e))

        # Catch any exception. This is non-critical and mustn't break stuff
        # elsewhere.
        except Exception as e: # pylint: disable=broad-except
            logger.exception(e, exc_info=True)