Пример #1
0
def multicall(conf, context, topic, msg, timeout, connection_pool):
    """Make a call that returns multiple times."""
    # TODO(pekowski): Remove all these comments in Havana.
    # For amqp_rpc_single_reply_queue = False,
    # Can't use 'with' for multicall, as it returns an iterator
    # that will continue to use the connection.  When it's done,
    # connection.close() will get called which will put it back into
    # the pool
    # For amqp_rpc_single_reply_queue = True,
    # The 'with' statement is mandatory for closing the connection
    LOG.debug(_('Making synchronous call on %s ...'), topic)
    msg_id = uuid.uuid4().hex
    msg.update({'_msg_id': msg_id})
    LOG.debug(_('MSG_ID is %s') % (msg_id))
    _add_unique_id(msg)
    pack_context(msg, context)

    # TODO(pekowski): Remove this flag and the code under the if clause
    #                 in Havana.
    if not conf.amqp_rpc_single_reply_queue:
        conn = ConnectionContext(conf, connection_pool)
        wait_msg = MulticallWaiter(conf, conn, timeout)
        conn.declare_direct_consumer(msg_id, wait_msg)
        conn.topic_send(topic, rpc_common.serialize_msg(msg), timeout)
    else:
        with _reply_proxy_create_sem:
            if not connection_pool.reply_proxy:
                connection_pool.reply_proxy = ReplyProxy(conf, connection_pool)
        msg.update({'_reply_q': connection_pool.reply_proxy.get_reply_q()})
        wait_msg = MulticallProxyWaiter(conf, msg_id, timeout, connection_pool)
        with ConnectionContext(conf, connection_pool) as conn:
            conn.topic_send(topic, rpc_common.serialize_msg(msg), timeout)
    return wait_msg
Пример #2
0
def _parse_check(rule):
    """
    Parse a single base check rule into an appropriate Check object.
    """

    # Handle the special checks
    if rule == '!':
        return FalseCheck()
    elif rule == '@':
        return TrueCheck()

    try:
        kind, match = rule.split(':', 1)
    except Exception:
        LOG.exception(_("Failed to understand rule %(rule)s") % locals())
        # If the rule is invalid, we'll fail closed
        return FalseCheck()

    # Find what implements the check
    if kind in _checks:
        return _checks[kind](kind, match)
    elif None in _checks:
        return _checks[None](kind, match)
    else:
        LOG.error(_("No handler for matches of kind %s") % kind)
        return FalseCheck()
Пример #3
0
 def _connect(self, params):
     """Connect to rabbit.  Re-establish any queues that may have
     been declared before if we are reconnecting.  Exceptions should
     be handled by the caller.
     """
     if self.connection:
         LOG.info(_("Reconnecting to AMQP server on "
                  "%(hostname)s:%(port)d") % params)
         try:
             self.connection.release()
         except self.connection_errors:
             pass
         # Setting this in case the next statement fails, though
         # it shouldn't be doing any network operations, yet.
         self.connection = None
     self.connection = kombu.connection.BrokerConnection(**params)
     self.connection_errors = self.connection.connection_errors
     if self.memory_transport:
         # Kludge to speed up tests.
         self.connection.transport.polling_interval = 0.0
     self.consumer_num = itertools.count(1)
     self.connection.connect()
     self.channel = self.connection.channel()
     # work around 'memory' transport bug in 1.1.3
     if self.memory_transport:
         self.channel._new_queue('ae.undeliver')
     for consumer in self.consumers:
         consumer.reconnect(self.channel)
     LOG.info(_('Connected to AMQP server on %(hostname)s:%(port)d') %
              params)
Пример #4
0
    def reconnect(self):
        """Handles reconnecting and re-establishing sessions and queues"""
        if self.connection.opened():
            try:
                self.connection.close()
            except qpid_exceptions.ConnectionError:
                pass

        attempt = 0
        delay = 1
        while True:
            broker = self.brokers[attempt % len(self.brokers)]
            attempt += 1

            try:
                self.connection_create(broker)
                self.connection.open()
            except qpid_exceptions.ConnectionError, e:
                msg_dict = dict(e=e, delay=delay)
                msg = _("Unable to connect to AMQP server: %(e)s. "
                        "Sleeping %(delay)s seconds") % msg_dict
                LOG.error(msg)
                time.sleep(delay)
                delay = min(2 * delay, 60)
            else:
                LOG.info(_('Connected to AMQP server on %s'), broker)
                break
Пример #5
0
    def _wait_child(self):
        try:
            # Don't block if no child processes have exited
            pid, status = os.waitpid(0, os.WNOHANG)
            if not pid:
                return None
        except OSError as exc:
            if exc.errno not in (errno.EINTR, errno.ECHILD):
                raise
            return None

        if os.WIFSIGNALED(status):
            sig = os.WTERMSIG(status)
            LOG.info(_("Child %(pid)d killed by signal %(sig)d"), dict(pid=pid, sig=sig))
        else:
            code = os.WEXITSTATUS(status)
            LOG.info(_("Child %(pid)s exited with status %(code)d"), dict(pid=pid, code=code))

        if pid not in self.children:
            LOG.warning(_("pid %d not in child list"), pid)
            return None

        wrap = self.children.pop(pid)
        wrap.children.remove(pid)
        return wrap
Пример #6
0
    def wait(self):
        """Loop waiting on children to die and respawning as necessary"""

        LOG.debug(_("Full set of CONF:"))
        CONF.log_opt_values(LOG, std_logging.DEBUG)

        while self.running:
            wrap = self._wait_child()
            if not wrap:
                # Yield to other threads if no children have exited
                # Sleep for a short time to avoid excessive CPU usage
                # (see bug #1095346)
                eventlet.greenthread.sleep(0.01)
                continue

            while self.running and len(wrap.children) < wrap.workers:
                self._start_child(wrap)

        if self.sigcaught:
            signame = {signal.SIGTERM: "SIGTERM", signal.SIGINT: "SIGINT"}[self.sigcaught]
            LOG.info(_("Caught %s, stopping children"), signame)

        for pid in self.children:
            try:
                os.kill(pid, signal.SIGTERM)
            except OSError as exc:
                if exc.errno != errno.ESRCH:
                    raise

        # Wait for children to die
        if self.children:
            LOG.info(_("Waiting on %d children to exit"), len(self.children))
            while self.children:
                self._wait_child()
Пример #7
0
    def run_periodic_tasks(self, context, raise_on_error=False):
        """Tasks to be run at a periodic interval."""
        for task_name, task in self._periodic_tasks:
            full_task_name = '.'.join([self.__class__.__name__, task_name])

            ticks_to_skip = self._ticks_to_skip[task_name]
            if ticks_to_skip > 0:
                LOG.debug(_("Skipping %(full_task_name)s, %(ticks_to_skip)s"
                            " ticks left until next run"),
                          dict(full_task_name=full_task_name,
                               ticks_to_skip=ticks_to_skip))
                self._ticks_to_skip[task_name] -= 1
                continue

            self._ticks_to_skip[task_name] = task._ticks_between_runs
            LOG.debug(_("Running periodic task %(full_task_name)s"),
                      dict(full_task_name=full_task_name))

            try:
                task(self, context)
            except Exception as e:
                if raise_on_error:
                    raise
                LOG.exception(_("Error during %(full_task_name)s:"
                                " %(e)s"),
                              dict(e=e, full_task_name=full_task_name))
Пример #8
0
    def _process_data(self, ctxt, version, method, args):
        """Process a message in a new thread.

        If the proxy object we have has a dispatch method
        (see rpc.dispatcher.RpcDispatcher), pass it the version,
        method, and args and let it dispatch as appropriate.  If not, use
        the old behavior of magically calling the specified method on the
        proxy we have here.
        """
        ctxt.update_store()
        try:
            rval = self.proxy.dispatch(ctxt, version, method, **args)
            # Check if the result was a generator
            if inspect.isgenerator(rval):
                for x in rval:
                    ctxt.reply(x, None, connection_pool=self.connection_pool)
            else:
                ctxt.reply(rval, None, connection_pool=self.connection_pool)
            # This final None tells multicall that it is done.
            ctxt.reply(ending=True, connection_pool=self.connection_pool)
        except rpc_common.ClientException as e:
            LOG.debug(_('Expected exception during message handling (%s)') %
                      e._exc_info[1])
            ctxt.reply(None, e._exc_info,
                       connection_pool=self.connection_pool,
                       log_failure=False)
        except Exception:
            # sys.exc_info() is deleted by LOG.exception().
            exc_info = sys.exc_info()
            LOG.error(_('Exception during message handling'),
                      exc_info=exc_info)
            ctxt.reply(None, exc_info, connection_pool=self.connection_pool)
Пример #9
0
    def __call__(self, message_data):
        """Consumer callback to call a method on a proxy object.

        Parses the message for validity and fires off a thread to call the
        proxy object method.

        Message data should be a dictionary with two keys:
            method: string representing the method to call
            args: dictionary of arg: value

        Example: {'method': 'echo', 'args': {'value': 42}}

        """
        # It is important to clear the context here, because at this point
        # the previous context is stored in local.store.context
        if hasattr(local.store, 'context'):
            del local.store.context
        rpc_common._safe_log(LOG.debug, _('received %s'), message_data)
        self.msg_id_cache.check_duplicate_message(message_data)
        ctxt = unpack_context(self.conf, message_data)
        method = message_data.get('method')
        args = message_data.get('args', {})
        version = message_data.get('version', None)
        if not method:
            LOG.warn(_('no method for message: %s') % message_data)
            ctxt.reply(_('No method for message: %s') % message_data,
                       connection_pool=self.connection_pool)
            return
        self.pool.spawn_n(self._process_data, ctxt, version, method, args)
Пример #10
0
 def _error_callback(exc):
     if isinstance(exc, qpid_exceptions.Empty):
         LOG.debug(_('Timed out waiting for RPC response: %s') %
                   str(exc))
         raise rpc_common.Timeout()
     else:
         LOG.exception(_('Failed to consume message from queue: %s') %
                       str(exc))
Пример #11
0
 def _error_callback(exc):
     if isinstance(exc, socket.timeout):
         LOG.debug(_('Timed out waiting for RPC response: %s') %
                   str(exc))
         raise rpc_common.Timeout()
     else:
         LOG.exception(_('Failed to consume message from queue: %s') %
                       str(exc))
         info['do_consume'] = True
Пример #12
0
def notify(context, publisher_id, event_type, priority, payload):
    """Sends a notification using the specified driver

    :param publisher_id: the source worker_type.host of the message
    :param event_type:   the literal type of event (ex. Instance Creation)
    :param priority:     patterned after the enumeration of Python logging
                         levels in the set (DEBUG, WARN, INFO, ERROR, CRITICAL)
    :param payload:       A python dictionary of attributes

    Outgoing message format includes the above parameters, and appends the
    following:

    message_id
      a UUID representing the id for this notification

    timestamp
      the GMT timestamp the notification was sent at

    The composite message will be constructed as a dictionary of the above
    attributes, which will then be sent via the transport mechanism defined
    by the driver.

    Message example::

        {'message_id': str(uuid.uuid4()),
         'publisher_id': 'compute.host1',
         'timestamp': timeutils.utcnow(),
         'priority': 'WARN',
         'event_type': 'compute.create_instance',
         'payload': {'instance_id': 12, ... }}

    """
    if priority not in log_levels:
        raise BadPriorityException(
            _('%s not in valid priorities') % priority)

    # Ensure everything is JSON serializable.
    payload = jsonutils.to_primitive(payload, convert_instances=True)

    msg = dict(message_id=str(uuid.uuid4()),
               publisher_id=publisher_id,
               event_type=event_type,
               priority=priority,
               payload=payload,
               timestamp=str(timeutils.utcnow()))

    for driver in _get_drivers():
        try:
            driver.notify(context, msg)
        except Exception as e:
            LOG.exception(_("Problem '%(e)s' attempting to "
                            "send to notification system. "
                            "Payload=%(payload)s")
                          % dict(e=e, payload=payload))
Пример #13
0
    def reconnect(self):
        """Handles reconnecting and re-establishing queues.
        Will retry up to self.max_retries number of times.
        self.max_retries = 0 means to retry forever.
        Sleep between tries, starting at self.interval_start
        seconds, backing off self.interval_stepping number of seconds
        each attempt.
        """

        attempt = 0
        while True:
            params = self.params_list[attempt % len(self.params_list)]
            attempt += 1
            try:
                self._connect(params)
                return
            except (IOError, self.connection_errors) as e:
                pass
            except Exception, e:
                # NOTE(comstud): Unfortunately it's possible for amqplib
                # to return an error not covered by its transport
                # connection_errors in the case of a timeout waiting for
                # a protocol response.  (See paste link in LP888621)
                # So, we check all exceptions for 'timeout' in them
                # and try to reconnect in this case.
                if 'timeout' not in str(e):
                    raise

            log_info = {}
            log_info['err_str'] = str(e)
            log_info['max_retries'] = self.max_retries
            log_info.update(params)

            if self.max_retries and attempt == self.max_retries:
                LOG.error(_('Unable to connect to AMQP server on '
                            '%(hostname)s:%(port)d after %(max_retries)d '
                            'tries: %(err_str)s') % log_info)
                # NOTE(comstud): Copied from original code.  There's
                # really no better recourse because if this was a queue we
                # need to consume on, we have no way to consume anymore.
                sys.exit(1)

            if attempt == 1:
                sleep_time = self.interval_start or 1
            elif attempt > 1:
                sleep_time += self.interval_stepping
            if self.interval_max:
                sleep_time = min(sleep_time, self.interval_max)

            log_info['sleep_time'] = sleep_time
            LOG.error(_('AMQP server on %(hostname)s:%(port)d is '
                        'unreachable: %(err_str)s. Trying again in '
                        '%(sleep_time)d seconds.') % log_info)
            time.sleep(sleep_time)
Пример #14
0
 def _wrap(*args, **kwargs):
     try:
         return f(*args, **kwargs)
     except UnicodeEncodeError:
         raise exception.DBInvalidUnicodeParameter()
     except sqla_exc.OperationalError as e:
         _raise_if_db_connection_lost(e, get_engine())
         _raise_if_deadlock_error(e, get_engine().name)
         # NOTE(comstud): A lot of code is checking for OperationalError
         # so let's not wrap it for now.
         raise
     # note(boris-42): We should catch unique constraint violation and
     # wrap it by our own DBDuplicateEntry exception. Unique constraint
     # violation is wrapped by IntegrityError.
     except sqla_exc.IntegrityError as e:
         # note(boris-42): SqlAlchemy doesn't unify errors from different
         # DBs so we must do this. Also in some tables (for example
         # instance_types) there are more than one unique constraint. This
         # means we should get names of columns, which values violate
         # unique constraint, from error message.
         _raise_if_duplicate_entry_error(e, get_engine().name)
         raise exception.DBError(e)
     except Exception as e:
         LOG.exception(_("DB exception wrapped."))
         raise exception.DBError(e)
Пример #15
0
def cast(conf, context, topic, msg, connection_pool):
    """Sends a message on a topic without waiting for a response."""
    LOG.debug(_('Making asynchronous cast on %s...'), topic)
    _add_unique_id(msg)
    pack_context(msg, context)
    with ConnectionContext(conf, connection_pool) as conn:
        conn.topic_send(topic, rpc_common.serialize_msg(msg))
Пример #16
0
def serialize_remote_exception(failure_info, log_failure=True):
    """Prepares exception data to be sent over rpc.

    Failure_info should be a sys.exc_info() tuple.

    """
    tb = traceback.format_exception(*failure_info)
    failure = failure_info[1]
    if log_failure:
        LOG.error(_("Returning exception %s to caller"), unicode(failure))
        LOG.error(tb)

    kwargs = {}
    if hasattr(failure, 'kwargs'):
        kwargs = failure.kwargs

    data = {
        'class': str(failure.__class__.__name__),
        'module': str(failure.__class__.__module__),
        'message': unicode(failure),
        'tb': tb,
        'args': failure.args,
        'kwargs': kwargs
    }

    json_data = jsonutils.dumps(data)

    return json_data
Пример #17
0
def _safe_log(log_func, msg, msg_data):
    """Sanitizes the msg_data field before logging."""
    SANITIZE = {'set_admin_password': [('args', 'new_pass')],
                'run_instance': [('args', 'admin_password')],
                'route_message': [('args', 'message', 'args', 'method_info',
                                   'method_kwargs', 'password'),
                                  ('args', 'message', 'args', 'method_info',
                                   'method_kwargs', 'admin_password')]}

    has_method = 'method' in msg_data and msg_data['method'] in SANITIZE
    has_context_token = '_context_auth_token' in msg_data
    has_token = 'auth_token' in msg_data

    if not any([has_method, has_context_token, has_token]):
        return log_func(msg, msg_data)

    msg_data = copy.deepcopy(msg_data)

    if has_method:
        for arg in SANITIZE.get(msg_data['method'], []):
            try:
                d = msg_data
                for elem in arg[:-1]:
                    d = d[elem]
                d[arg[-1]] = '<SANITIZED>'
            except KeyError, e:
                LOG.info(_('Failed to sanitize %(item)s. Key error %(err)s'),
                         {'item': arg,
                          'err': e})
Пример #18
0
    def start(self, interval, initial_delay=None):
        self._running = True
        done = event.Event()

        def _inner():
            if initial_delay:
                greenthread.sleep(initial_delay)

            try:
                while self._running:
                    start = timeutils.utcnow()
                    self.f(*self.args, **self.kw)
                    end = timeutils.utcnow()
                    if not self._running:
                        break
                    delay = interval - timeutils.delta_seconds(start, end)
                    if delay <= 0:
                        LOG.warn(_('task run outlasted interval by %s sec') %
                                 -delay)
                    greenthread.sleep(delay if delay > 0 else 0)
            except LoopingCallDone, e:
                self.stop()
                done.send(e.retvalue)
            except Exception:
                LOG.exception(_('in looping call'))
                done.send_exception(*sys.exc_info())
                return
Пример #19
0
def fanout_cast(conf, context, topic, msg, connection_pool):
    """Sends a message on a fanout exchange without waiting for a response."""
    LOG.debug(_('Making asynchronous fanout cast...'))
    _add_unique_id(msg)
    pack_context(msg, context)
    with ConnectionContext(conf, connection_pool) as conn:
        conn.fanout_send(topic, rpc_common.serialize_msg(msg))
Пример #20
0
 def deprecated(self, msg, *args, **kwargs):
     stdmsg = _("Deprecated: %s") % msg
     if CONF.fatal_deprecations:
         self.critical(stdmsg, *args, **kwargs)
         raise DeprecatedConfig(msg=stdmsg)
     else:
         self.warn(stdmsg, *args, **kwargs)
Пример #21
0
 def _process_data(self, message_data):
     msg_id = message_data.pop('_msg_id', None)
     waiter = self._call_waiters.get(msg_id)
     if not waiter:
         LOG.warn(_('no calling threads waiting for msg_id : %s'
                    ', message : %s') % (msg_id, message_data))
     else:
         waiter.put(message_data)
Пример #22
0
    def _pipe_watcher(self):
        # This will block until the write end is closed when the parent
        # dies unexpectedly
        self.readpipe.read()

        LOG.info(_("Parent process has died unexpectedly, exiting"))

        sys.exit(1)
Пример #23
0
 def add_call_waiter(self, waiter, msg_id):
     self._num_call_waiters += 1
     if self._num_call_waiters > self._num_call_waiters_wrn_threshhold:
         LOG.warn(_('Number of call waiters is greater than warning '
                    'threshhold: %d. There could be a MulticallProxyWaiter '
                    'leak.') % self._num_call_waiters_wrn_threshhold)
         self._num_call_waiters_wrn_threshhold *= 2
     self._call_waiters[msg_id] = waiter
Пример #24
0
 def sfc_init_consumer(self, context, **kwargs):
     """
     This function is called when ever any consumer is started
     """
     LOG.debug(_("In Init Consumer for SFC.......KWArgs = %s"), str(kwargs))
     payload = kwargs["consumer"]
     payload = payload["payload"]
     return self.sfcdelta.sfc_init(self.context, payload["version"], payload["hostname"])
Пример #25
0
 def _callback(raw_message):
     message = self.channel.message_to_python(raw_message)
     try:
         msg = rpc_common.deserialize_msg(message.payload)
         callback(msg)
     except Exception:
         LOG.exception(_("Failed to process message... skipping it."))
     finally:
         message.ack()
Пример #26
0
 def run(self, key):
     if not self._ring_has(key):
         LOG.warn(
             _("No key defining hosts for topic '%s', "
               "see ringfile") % (key, )
         )
         return []
     host = next(self.ring0[key])
     return [(key + '.' + host, host)]
Пример #27
0
 def delete_category_nf_map(self, context, networkfunction_id, category_id):
     LOG.debug(_("Delete category_networkfunction %s"), networkfunction_id)
     v = self.get_category_nf_map(context, networkfunction_id, category_id)
     self.db.delete_category_networkfunction(context, category_id, networkfunction_id)
     data = v
     v.update({"operation": "delete"})
     delta = {}
     delta.update({"category_networkfunctions_delta": v})
     result_delta = self.sfcdelta.create_category_networkfunctions_delta(context, delta)
Пример #28
0
def _get_not_supported_column(col_name_col_instance, column_name):
    try:
        column = col_name_col_instance[column_name]
    except KeyError:
        msg = _(
            "Please specify column %s in col_name_col_instance "
            "param. It is required because column has unsupported "
            "type by sqlite)."
        )
        raise ColumnError(msg % column_name)

    if not isinstance(column, Column):
        msg = _(
            "col_name_col_instance param has wrong type of "
            "column instance for column %s It should be instance "
            "of sqlalchemy.Column."
        )
        raise ColumnError(msg % column_name)
    return column
Пример #29
0
 def _wrap(*args, **kw):
     try:
         return f(*args, **kw)
     except Exception, e:
         if not isinstance(e, Error):
             #exc_type, exc_value, exc_traceback = sys.exc_info()
             logging.exception(_('Uncaught exception'))
             #logging.error(traceback.extract_stack(exc_traceback))
             raise Error(str(e))
         raise
Пример #30
0
 def consume(self):
     """Fetch the message and pass it to the callback object"""
     message = self.receiver.fetch()
     try:
         msg = rpc_common.deserialize_msg(message.content)
         self.callback(msg)
     except Exception:
         LOG.exception(_("Failed to process message... skipping it."))
     finally:
         self.session.acknowledge(message)