예제 #1
0
    def process_event(self, event):
        """Trigger a state change in response to the provided event."""
        current = self._current
        if current is None:
            raise excp.InvalidState(
                _("Can only process events after"
                  " being initialized (not before)"))
        if self._states[current.name]['terminal']:
            raise excp.InvalidState(
                _("Can not transition from terminal "
                  "state '%(state)s' on event '%(event)s'") % {
                      'state': current.name,
                      'event': event
                  })
        if event not in self._transitions[current.name]:
            raise excp.InvalidState(
                _("Can not transition from state '%(state)s' on "
                  "event '%(event)s' (no defined transition)") % {
                      'state': current.name,
                      'event': event
                  })
        replacement = self._transitions[current.name][event]
        if current.on_exit is not None:
            current.on_exit(current.name, event)
        if replacement.on_enter is not None:
            replacement.on_enter(replacement.name, event)
        self._current = replacement

        # clear _target if we've reached it
        if (self._target_state is not None
                and self._target_state == replacement.name):
            self._target_state = None
        # if new state has a different target, update the target
        if self._states[replacement.name]['target'] is not None:
            self._target_state = self._states[replacement.name]['target']
예제 #2
0
def verify_node_for_deallocation(node, allocation):
    """Verify that allocation can be removed for the node.

    :param node: a node object
    :param allocation: an allocation object associated with the node
    """
    if node.maintenance:
        # Allocations can always be removed in the maintenance mode.
        return

    if (node.target_provision_state
            and node.provision_state not in states.UPDATE_ALLOWED_STATES):
        msg = (_("Cannot remove allocation %(uuid)s for node %(node)s, "
                 "because the node is in state %(state)s where updates are "
                 "not allowed (and maintenance mode is off)") % {
                     'node': node.uuid,
                     'uuid': allocation.uuid,
                     'state': node.provision_state
                 })
        raise exception.InvalidState(msg)

    if node.provision_state == states.ACTIVE:
        msg = (_("Cannot remove allocation %(uuid)s for node %(node)s, "
                 "because the node is active (and maintenance mode is off)") %
               {
                   'node': node.uuid,
                   'uuid': allocation.uuid
               })
        raise exception.InvalidState(msg)
예제 #3
0
파일: fsm.py 프로젝트: zweiustc/ironic
    def add_state(self,
                  state,
                  on_enter=None,
                  on_exit=None,
                  target=None,
                  terminal=None,
                  stable=False):
        """Adds a given state to the state machine.

        :param stable: Use this to specify that this state is a stable/passive
                       state. A state must have been previously defined as
                       'stable' before it can be used as a 'target'
        :param target: The target state for 'state' to go to.  Before a state
                       can be used as a target it must have been previously
                       added and specified as 'stable'

        Further arguments are interpreted as for parent method ``add_state``.
        """
        if target is not None:
            if target not in self._states:
                raise excp.InvalidState(
                    _("Target state '%s' does not exist") % target)
            if not self._states[target]['stable']:
                raise excp.InvalidState(
                    _("Target state '%s' is not a 'stable' state") % target)
        super(FSM, self).add_state(state,
                                   terminal=terminal,
                                   on_enter=on_enter,
                                   on_exit=on_exit)
        self._states[state].update({
            'stable': stable,
            'target': target,
        })
예제 #4
0
    def add_state(self,
                  state,
                  on_enter=None,
                  on_exit=None,
                  target=None,
                  terminal=None):
        """Adds a given state to the state machine.

        The on_enter and on_exit callbacks, if provided will be expected to
        take two positional parameters, these being the state being exited (for
        on_exit) or the state being entered (for on_enter) and a second
        parameter which is the event that is being processed that caused the
        state transition.
        """
        if state in self._states:
            raise excp.Duplicate(_("State '%s' already defined") % state)
        if on_enter is not None:
            if not six.callable(on_enter):
                raise ValueError(_("On enter callback must be callable"))
        if on_exit is not None:
            if not six.callable(on_exit):
                raise ValueError(_("On exit callback must be callable"))
        if target is not None and target not in self._states:
            raise excp.InvalidState(
                _("Target state '%s' does not exist") % target)

        self._states[state] = {
            'terminal': bool(terminal),
            'reactions': {},
            'on_enter': on_enter,
            'on_exit': on_exit,
            'target': target,
        }
        self._transitions[state] = OrderedDict()
예제 #5
0
    def test_process_event_fsm_raises(self):
        self.task.process_event = task_manager.TaskManager.process_event
        self.fsm.process_event.side_effect = exception.InvalidState('test')

        self.assertRaises(exception.InvalidState, self.task.process_event,
                          self.task, 'fake')
        self.assertEqual(0, self.task.spawn_after.call_count)
        self.assertFalse(self.task.node.save.called)
예제 #6
0
    def _validate_target_state(self, target):
        """Validate the target state.

        A target state must be a valid state that is 'stable'.

        :param target: The target state
        :raises: exception.InvalidState if it is an invalid target state
        """
        if target is None:
            return

        if target not in self._states:
            raise excp.InvalidState(
                _("Target state '%s' does not exist") % target)
        if not self.is_stable(target):
            raise excp.InvalidState(
                _("Target state '%s' is not a 'stable' state") % target)
예제 #7
0
파일: fsm.py 프로젝트: johalee/Ironic
    def add_state(self,
                  state,
                  on_enter=None,
                  on_exit=None,
                  target=None,
                  terminal=None,
                  stable=False):
        """Adds a given state to the state machine.

        The on_enter and on_exit callbacks, if provided will be expected to
        take two positional parameters, these being the state being exited (for
        on_exit) or the state being entered (for on_enter) and a second
        parameter which is the event that is being processed that caused the
        state transition.

        :param stable: Use this to specify that this state is a stable/passive
                       state. A state must have been previously defined as
                       'stable' before it can be used as a 'target'
        :param target: The target state for 'state' to go to.  Before a state
                       can be used as a target it must have been previously
                       added and specified as 'stable'
        """
        if state in self._states:
            raise excp.Duplicate(_("State '%s' already defined") % state)
        if on_enter is not None:
            if not six.callable(on_enter):
                raise ValueError(_("On enter callback must be callable"))
        if on_exit is not None:
            if not six.callable(on_exit):
                raise ValueError(_("On exit callback must be callable"))
        if target is not None and target not in self._states:
            raise excp.InvalidState(
                _("Target state '%s' does not exist") % target)
        if target is not None and not self._states[target]['stable']:
            raise excp.InvalidState(
                _("Target state '%s' is not a 'stable' state") % target)

        self._states[state] = {
            'terminal': bool(terminal),
            'reactions': {},
            'on_enter': on_enter,
            'on_exit': on_exit,
            'target': target,
            'stable': stable,
        }
        self._transitions[state] = OrderedDict()
예제 #8
0
 def wrapper(*args, **kwargs):
     try:
         return func(*args, **kwargs)
     except (automaton_exceptions.InvalidState,
             automaton_exceptions.NotInitialized,
             automaton_exceptions.FrozenMachine,
             automaton_exceptions.NotFound) as e:
         raise excp.InvalidState(str(e))
     except automaton_exceptions.Duplicate as e:
         raise excp.Duplicate(str(e))
예제 #9
0
    def is_stable(self, state):
        """Is the state stable?

        :param state: the state of interest
        :raises: InvalidState if the state is invalid
        :returns: True if it is a stable state; False otherwise
        """
        try:
            return self._states[state]['stable']
        except KeyError:
            raise excp.InvalidState(_("State '%s' does not exist") % state)
예제 #10
0
    def initialize(self, state=None):
        """Sets up the state machine.

        sets the current state to the specified state, or start_state
        if no state was specified..
        """
        if state is None:
            state = self._start_state
        if state not in self._states:
            raise excp.NotFound(
                _("Can not start from an undefined"
                  " state '%s'") % (state))
        if self._states[state]['terminal']:
            raise excp.InvalidState(
                _("Can not start from a terminal"
                  " state '%s'") % (state))
        self._current = _Jump(state, None, None)