diff options
author | Devananda van der Veen <devananda.vdv@gmail.com> | 2015-01-26 07:39:41 -0800 |
---|---|---|
committer | Devananda van der Veen <devananda.vdv@gmail.com> | 2015-02-04 19:11:07 -0800 |
commit | 5dbd06f89da2ef8395460d0c4af8f4bfc1963030 (patch) | |
tree | e587b1f82f9db83f6402cd6baa1247fc735d424f /ironic/conductor | |
parent | b0af29e66478eeb48d42ba7be720f9ae06ab1044 (diff) | |
download | ironic-5dbd06f89da2ef8395460d0c4af8f4bfc1963030.tar.gz |
Add MANAGEABLE state and associated transitions
This patch adds the MANAGEABLE state, and associated transitions to and
from AVAILABLE, as well as a new RPC method to initiate transitions
between provisioning states.
It also adds a new VERBS entity to ironic/common/states.py to hold the
action-phrases, as described in blueprint new-ironic-state-machine. This
provides a single place to check whether a requested target state is
allowed to be requested by checking if the value is "in" the keys of
this dictionary. It also provides a mapping for two phrases which are
currently inconsistent:
target:deleted -> action:delete
target:active -> action:deploy
It updates the API controller for nodes.py without changing the HTTP
status codes which are returned in exception cases. The changes in unit
tests now prepare the node appropriately, but do not change the
assertions being tested.
Juno allowed the rebuild of a failed deploy to be initiated by PUTting
a target state of "active"; this behavior, while inconsistent with the
new state machine, is added to the state model for compatibility, now
that stronger checking is done within the API service, based on the
actual modelling of state transitions.
Implements: blueprint new-ironic-state-machine
Co-Authored-By: David Shrewsbury <shrewsbury.dave@gmail.com>
Change-Id: Id0af5a607b7432d287eef643c1e30e324dc4f879
Diffstat (limited to 'ironic/conductor')
-rw-r--r-- | ironic/conductor/manager.py | 60 | ||||
-rw-r--r-- | ironic/conductor/rpcapi.py | 22 |
2 files changed, 63 insertions, 19 deletions
diff --git a/ironic/conductor/manager.py b/ironic/conductor/manager.py index 90e2e426f..f6251a0c4 100644 --- a/ironic/conductor/manager.py +++ b/ironic/conductor/manager.py @@ -171,7 +171,7 @@ class ConductorManager(periodic_task.PeriodicTasks): """Ironic Conductor manager main class.""" # NOTE(rloo): This must be in sync with rpcapi.ConductorAPI's. - RPC_API_VERSION = '1.22' + RPC_API_VERSION = '1.23' target = messaging.Target(version=RPC_API_VERSION) @@ -600,8 +600,7 @@ class ConductorManager(periodic_task.PeriodicTasks): exception.NodeLocked, exception.NodeInMaintenance, exception.InstanceDeployFailure, - exception.InvalidParameterValue, - exception.MissingParameterValue) + exception.InvalidStateRequested) def do_node_deploy(self, context, node_id, rebuild=False, configdrive=None): """RPC method to initiate deployment to a node. @@ -621,6 +620,8 @@ class ConductorManager(periodic_task.PeriodicTasks): :raises: NodeInMaintenance if the node is in maintenance mode. :raises: NoFreeConductorWorker when there is no free worker to start async task. + :raises: InvalidStateRequested when the requested state is not a valid + target from the current state. """ LOG.debug("RPC do_node_deploy called for node %s." % node_id) @@ -666,18 +667,14 @@ class ConductorManager(periodic_task.PeriodicTasks): configdrive), err_handler=provisioning_error_handler) except exception.InvalidState: - raise exception.InstanceDeployFailure(_( - "Request received to %(what)s %(node)s, but " - "this is not possible in the current state of " - "'%(state)s'. ") % {'what': event, - 'node': node.uuid, - 'state': node.provision_state}) + raise exception.InvalidStateRequested( + action=event, node=task.node.uuid, + state=task.node.provision_state) @messaging.expected_exceptions(exception.NoFreeConductorWorker, exception.NodeLocked, exception.InstanceDeployFailure, - exception.InvalidParameterValue, - exception.MissingParameterValue) + exception.InvalidStateRequested) def do_node_tear_down(self, context, node_id): """RPC method to tear down an existing node deployment. @@ -689,12 +686,13 @@ class ConductorManager(periodic_task.PeriodicTasks): :raises: InstanceDeployFailure :raises: NoFreeConductorWorker when there is no free worker to start async task + :raises: InvalidStateRequested when the requested state is not a valid + target from the current state. """ LOG.debug("RPC do_node_tear_down called for node %s." % node_id) with task_manager.acquire(context, node_id, shared=False) as task: - node = task.node try: # NOTE(ghe): Valid power driver values are needed to perform # a tear-down. Deploy info is useful to purge the cache but not @@ -703,8 +701,8 @@ class ConductorManager(periodic_task.PeriodicTasks): except (exception.InvalidParameterValue, exception.MissingParameterValue) as e: raise exception.InstanceDeployFailure(_( - "RPC do_node_tear_down failed to validate power info. " - "Error: %(msg)s") % {'msg': e}) + "Failed to validate power driver interface. " + "Can not delete instance. Error: %(msg)s") % {'msg': e}) try: task.process_event('delete', @@ -712,10 +710,36 @@ class ConductorManager(periodic_task.PeriodicTasks): call_args=(do_node_tear_down, task), err_handler=provisioning_error_handler) except exception.InvalidState: - raise exception.InstanceDeployFailure(_( - "RPC do_node_tear_down " - "not allowed for node %(node)s in state %(state)s") - % {'node': node_id, 'state': node.provision_state}) + raise exception.InvalidStateRequested( + action='delete', node=task.node.uuid, + state=task.node.provision_state) + + @messaging.expected_exceptions(exception.NoFreeConductorWorker, + exception.NodeLocked, + exception.InvalidParameterValue, + exception.MissingParameterValue, + exception.InvalidStateRequested) + def do_provisioning_action(self, context, node_id, action): + """RPC method to initiate certain provisioning state transitions. + + Initiate a provisioning state change through the state machine, + rather than through an RPC call to do_node_deploy / do_node_tear_down + + :param context: an admin context. + :param node_id: the id or uuid of a node. + :param action: an action. One of ironic.common.states.VERBS + :raises: InvalidParameterValue + :raises: InvalidStateRequested + :raises: NoFreeConductorWorker + + """ + with task_manager.acquire(context, node_id, shared=False) as task: + try: + task.process_event(action) + except exception.InvalidState: + raise exception.InvalidStateRequested( + action=action, node=task.node.uuid, + state=task.node.provision_state) @periodic_task.periodic_task( spacing=CONF.conductor.sync_power_state_interval) diff --git a/ironic/conductor/rpcapi.py b/ironic/conductor/rpcapi.py index a3115985f..9524123d4 100644 --- a/ironic/conductor/rpcapi.py +++ b/ironic/conductor/rpcapi.py @@ -65,11 +65,12 @@ class ConductorAPI(object): | 1.21 - Added get_node_vendor_passthru_methods and | get_driver_vendor_passthru_methods | 1.22 - Added configdrive parameter to do_node_deploy. + | 1.23 - Added do_provisioning_action """ # NOTE(rloo): This must be in sync with manager.ConductorManager's. - RPC_API_VERSION = '1.22' + RPC_API_VERSION = '1.23' def __init__(self, topic=None): super(ConductorAPI, self).__init__() @@ -303,6 +304,25 @@ class ConductorAPI(object): cctxt = self.client.prepare(topic=topic or self.topic, version='1.6') return cctxt.call(context, 'do_node_tear_down', node_id=node_id) + def do_provisioning_action(self, context, node_id, action, topic=None): + """Signal to conductor service to perform the given action on a node. + + :param context: request context. + :param node_id: node id or uuid. + :param action: an action. One of ironic.common.states.VERBS + :param topic: RPC topic. Defaults to self.topic. + :raises: InvalidParameterValue + :raises: NoFreeConductorWorker when there is no free worker to start + async task. + :raises: InvalidStateRequested if the requested action can not + be performed. + + This encapsulates some provisioning actions in a single call. + """ + cctxt = self.client.prepare(topic=topic or self.topic, version='1.23') + return cctxt.call(context, 'do_provisioning_action', + node_id=node_id, action=action) + def validate_driver_interfaces(self, context, node_id, topic=None): """Validate the `core` and `standardized` interfaces for drivers. |