ironic.conductor.task_manager module¶
A context manager to perform a series of tasks on a set of resources.
TaskManager
is a context manager, created on-demand to allow
synchronized access to a node and its resources.
The TaskManager
will, by default, acquire an exclusive lock on
a node for the duration that the TaskManager instance exists. You may
create a TaskManager instance without locking by passing “shared=True”
when creating it, but certain operations on the resources held by such
an instance of TaskManager will not be possible. Requiring this exclusive
lock guards against parallel operations interfering with each other.
A shared lock is useful when performing non-interfering operations, such as validating the driver interfaces.
An exclusive lock is stored in the database to coordinate between
ironic.conductor.manager
instances, that are typically deployed on
different hosts.
TaskManager
methods, as well as driver methods, may be decorated to
determine whether their invocation requires an exclusive lock.
The TaskManager instance exposes certain node resources and properties as attributes that you may access:
- task.context
The context passed to TaskManager()
- task.shared
False if Node is locked, True if it is not locked. (The ‘shared’ kwarg arg of TaskManager())
- task.node
The Node object
- task.ports
Ports belonging to the Node
- task.portgroups
Portgroups belonging to the Node
- task.volume_connectors
Storage connectors belonging to the Node
- task.volume_targets
Storage targets assigned to the Node
- task.driver
The Driver for the Node, or the Driver based on the ‘driver_name’ kwarg of TaskManager().
Example usage:
with task_manager.acquire(context, node_id, purpose='power on') as task:
task.driver.power.power_on(task.node)
If you need to execute task-requiring code in a background thread, the TaskManager instance provides an interface to handle this for you, making sure to release resources when the thread finishes (successfully or if an exception occurs). Common use of this is within the Manager like so:
with task_manager.acquire(context, node_id, purpose='some work') as task:
<do some work>
task.spawn_after(self._spawn_worker,
utils.node_power_action, task, new_state)
All exceptions that occur in the current GreenThread as part of the spawn handling are re-raised. You can specify a hook to execute custom code when such exceptions occur. For example, the hook is a more elegant solution than wrapping the “with task_manager.acquire()” with a try..exception block. (Note that this hook does not handle exceptions raised in the background thread.):
def on_error(e):
if isinstance(e, Exception):
...
with task_manager.acquire(context, node_id, purpose='some work') as task:
<do some work>
task.set_spawn_error_hook(on_error)
task.spawn_after(self._spawn_worker,
utils.node_power_action, task, new_state)
- class ironic.conductor.task_manager.TaskManager(context, node_id, shared=False, purpose='unspecified action', retry=True, patient=False, load_driver=True)[source]¶
Bases:
object
Context manager for tasks.
This class wraps the locking, driver loading, and acquisition of related resources (eg, Node and Ports) when beginning a unit of work.
- property node¶
- property portgroups¶
- property ports¶
- process_event(event, callback=None, call_args=None, call_kwargs=None, err_handler=None, target_state=None, last_error=None)[source]¶
Process the given event for the task’s current state.
- Parameters:
event – the name of the event to process
callback – optional callback to invoke upon event transition
call_args – optional args to pass to the callback method
call_kwargs – optional kwargs to pass to the callback method
err_handler – optional error handler to invoke if the callback fails, eg. because there are no workers available (err_handler should accept arguments node, prev_prov_state, and prev_target_state)
target_state – if specified, the target provision state for the node. Otherwise, use the target state from the fsm
last_error – last error to set on the node together with the state transition.
- Raises:
InvalidState if the event is not allowed by the associated state machine
- release_resources()[source]¶
Unlock a node and release resources.
If an exclusive lock is held, unlock the node. Reset attributes to make it clear that this instance of TaskManager should no longer be accessed.
- set_spawn_error_hook(_on_error_method, *args, **kwargs)[source]¶
Create a hook to handle exceptions when spawning a task.
Create a hook that gets called upon an exception being raised from spawning a background thread to do a task.
- Parameters:
_on_error_method – a callable object, it’s first parameter should accept the Exception object that was raised.
args – additional args passed to the callable object.
kwargs – additional kwargs passed to the callable object.
- spawn_after(_spawn_method, *args, **kwargs)[source]¶
Call this to spawn a thread to complete the task.
The specified method will be called when the TaskManager instance exits.
- Parameters:
_spawn_method – a method that returns a GreenThread object
args – args passed to the method.
kwargs – additional kwargs passed to the method.
- upgrade_lock(purpose=None, retry=None)[source]¶
Upgrade a shared lock to an exclusive lock.
Also reloads node object from the database. If lock is already exclusive only changes the lock purpose when provided with one.
- Parameters:
purpose – optionally change the purpose of the lock
retry – whether to retry locking if it fails, the class-level value is used by default
- Raises:
NodeLocked if an exclusive lock remains on the node after “node_locked_retry_attempts”
- property volume_connectors¶
- property volume_targets¶
- ironic.conductor.task_manager.acquire(context, *args, **kwargs)[source]¶
Shortcut for acquiring a lock on a Node.
- Parameters:
context – Request context.
- Returns:
An instance of
TaskManager
.
- ironic.conductor.task_manager.require_exclusive_lock(f)[source]¶
Decorator to require an exclusive lock.
Decorated functions must take a
TaskManager
as the first parameter. Decorated class methods should take aTaskManager
as the first parameter after “self”.