The 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.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, driver_name=None, purpose='unspecified action')[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.

process_event(event, callback=None, call_args=None, call_kwargs=None, err_handler=None, target_state=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
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)[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
Raises:NodeLocked if an exclusive lock remains on the node after “node_locked_retry_attempts”