Example #1
0
    def execute(self, method_name, params):
        """Execute the given method on the handler.

        Checks to make sure the method is valid and allowed perform executing
        the method.
        """
        if method_name in self._meta.allowed_methods:
            try:
                method = getattr(self, method_name)
            except AttributeError:
                raise HandlerNoSuchMethodError(method_name)
            else:
                # Handler methods are predominantly transactional and thus
                # blocking/synchronous. Genuinely non-blocking/asynchronous
                # methods must out themselves explicitly.
                if IAsynchronous.providedBy(method):
                    # The @asynchronous decorator will DTRT.
                    return method(params)
                else:
                    # This is going to block and hold a database connection so
                    # we limit its concurrency.
                    return concurrency.webapp.run(
                        deferToDatabase, transactional(method), params)
        else:
            raise HandlerNoSuchMethodError(method_name)
Example #2
0
 def query(self, system_id, context):
     """Performs the power query action for `system_id`."""
     exc_info = None, None, None
     for waiting_time in self.wait_time:
         try:
             # Power queries are predominantly transactional and thus
             # blocking/synchronous. Genuinely non-blocking/asynchronous
             # methods must out themselves explicitly.
             if IAsynchronous.providedBy(self.power_query):
                 # The @asynchronous decorator will DTRT.
                 state = yield self.power_query(system_id, context)
             else:
                 state = yield deferToThread(
                     self.power_query, system_id, context
                 )
         except PowerFatalError:
             raise  # Don't retry.
         except PowerError:
             exc_info = sys.exc_info()
             # Wait before retrying.
             yield pause(waiting_time, self.clock)
         else:
             returnValue(state)
     else:
         raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])
Example #3
0
    def execute(self, method_name, params):
        """Execute the given method on the handler.

        Checks to make sure the method is valid and allowed perform executing
        the method.
        """
        if method_name in self._meta.allowed_methods:
            try:
                method = getattr(self, method_name)
            except AttributeError:
                raise HandlerNoSuchMethodError(method_name)
            else:
                # Handler methods are predominantly transactional and thus
                # blocking/synchronous. Genuinely non-blocking/asynchronous
                # methods must out themselves explicitly.
                if IAsynchronous.providedBy(
                    method
                ) or asyncio.iscoroutinefunction(method):
                    # Running in the io thread so clear RBAC now.
                    rbac.clear()

                    # Reload the user from the database.
                    d = concurrency.webapp.run(
                        deferToDatabase,
                        transactional(self.user.refresh_from_db),
                    )
                    d.addCallback(lambda _: ensureDeferred(method(params)))
                    return d
                else:

                    @wraps(method)
                    @transactional
                    def prep_user_execute(params):
                        # Clear RBAC and reload the user to ensure that
                        # its up to date. `rbac.clear` must be done inside
                        # the thread because it uses thread locals internally.
                        rbac.clear()
                        self.user.refresh_from_db()

                        # Perform the work in the database.
                        return self._call_method_track_queries(
                            method_name, method, params
                        )

                    # Force the name of the function to include the handler
                    # name so the debug logging is useful.
                    prep_user_execute.__name__ = "%s.%s" % (
                        self.__class__.__name__,
                        method_name,
                    )

                    # This is going to block and hold a database connection so
                    # we limit its concurrency.
                    return concurrency.webapp.run(
                        deferToDatabase, prep_user_execute, params
                    )
        else:
            raise HandlerNoSuchMethodError(method_name)
Example #4
0
    def perform_power(self, power_func, state_desired, system_id, context):
        """Provides the logic to perform the power actions.

        :param power_func: Function used to change the power state of the
            node. Typically this will be `self.power_on` or `self.power_off`.
        :param state_desired: The desired state for this node to be in,
            typically "on" or "off".
        :param system_id: The node's system ID.
        """

        state = "unknown"
        exc_info = None, None, None

        for waiting_time in self.wait_time:
            # Try to change state.
            try:
                # Power methods are predominantly transactional and thus
                # blocking/synchronous. Genuinely non-blocking/asynchronous
                # methods must out themselves explicitly.
                if IAsynchronous.providedBy(power_func):
                    # The @asynchronous decorator will DTRT.
                    yield power_func(system_id, context)
                else:
                    yield deferToThread(power_func, system_id, context)
            except PowerFatalError:
                raise  # Don't retry.
            except PowerError:
                exc_info = sys.exc_info()
                # Wait before retrying.
                yield pause(waiting_time, self.clock)
            else:
                # LP:1768659 - If the power driver isn't queryable(manual)
                # checking the power state will always fail.
                if not self.queryable:
                    return
                # Wait before checking state.
                yield pause(waiting_time, self.clock)
                # Try to get power state.
                try:
                    # Power queries are predominantly transactional and thus
                    # blocking/synchronous. Genuinely non-blocking/asynchronous
                    # methods must out themselves explicitly.
                    if IAsynchronous.providedBy(self.power_query):
                        # The @asynchronous decorator will DTRT.
                        state = yield self.power_query(system_id, context)
                    else:
                        state = yield deferToThread(self.power_query,
                                                    system_id, context)
                except PowerFatalError:
                    raise  # Don't retry.
                except PowerError:
                    exc_info = sys.exc_info()
                else:
                    # If state is now the correct state, done.
                    if state == state_desired:
                        return

        if exc_info == (None, None, None):
            # No error found, so communication to the BMC is good, state must
            # have not changed in the elapsed time. That is the only reason we
            # should make it this far.
            raise PowerError(
                "Failed to power %s. BMC never transitioned from %s to %s." %
                (system_id, state, state_desired))
        else:
            # Report the last error.
            raise exc_info[0](exc_info[1]).with_traceback(exc_info[2])