Skip to content

Create a Control Extension

A control extension implements the interface defined by the Chaos Toolkit to support the Controls element of the specification.

Controls are good for changing the experiment or its environment during execution. They have the power to impact the experiment, configuration, secrets on the fly, which is unlike probes and actions.

Controls Interface

When implementing a control module, you must simply define a set of functions that are called by the Chaos Toolkit when executing the experiment.

Tip

All of these functions are optional, only implement the one you need.

from typing import Any, Dict, List

from chaoslib.types import Activity, Configuration, \
    Experiment, Hypothesis, Journal, Run, Secrets, Settings


def configure_control(configuration: Configuration = None,
                      secrets: Secrets = None, settings: Settings = None,
                      experiment: Experiment = None):
    """
    Configure the control's global state

    This is called once only per Chaos Toolkit's run and should be used to
    initialize any state your control may require.

    The `settings` are only passed when the control is declared in the
    settings file of the Chaos Toolkit.
    """
    pass


def cleanup_control():
    """
    Cleanup the control's global state

    Called once only during the experiment's execution.
    """
    pass


def before_loading_experiment_control(context: str, **kwargs):
    """
    before loading the experiment from its source.

    The context is the file path or URL given to the loader. Use this loader
    if you want to interact with that source before it is loaded.
    """
    pass


def after_loading_experiment_control(context: str, state: Experiment, **kwargs):
    """
    after loading the experiment from its source.

    Use this loader if you want to interact with the experiment once it's been
    loaded and parsed but before the validation or execution take place.
    """
    pass


def before_experiment_control(context: Experiment,
                              configuration: Configuration = None,
                              secrets: Secrets = None, **kwargs):
    """
    before-control of the experiment's execution

    Called by the Chaos Toolkit before the experiment's begin but after the
    configuration and secrets have been loaded.
    """
    pass


def after_experiment_control(context: Experiment, state: Journal, 
                             configuration: Configuration = None,
                             secrets: Secrets = None, **kwargs):
    """
    after-control of the experiment's execution

    Called by the Chaos Toolkit after the experiment's completed. It passes the
    journal of the execution. At that stage, the after control has no influence
    over the execution however. Please see
    https://docs.chaostoolkit.org/reference/api/journal/#journal-elements
    for more information about the journal.
    """
    pass


def before_hypothesis_control(context: Hypothesis,
                              configuration: Configuration = None,
                              secrets: Secrets = None, **kwargs):
    """
    before-control of the hypothesis's execution

    Called by the Chaos Toolkit before the steady-state hypothesis is
    applied.
    """
    pass


def after_hypothesis_control(context: Hypothesis, state: Dict[str, Any],
                             configuration: Configuration = None,
                             secrets: Secrets = None, **kwargs):
    """
    after-control of the hypothesis's execution

    Called by the Chaos Toolkit after the steady-state hypothesis is
    complete. The `state` contains the result of the hypothesis. Refer to
    https://docs.chaostoolkit.org/reference/api/journal/#steady-state-outcomes
    for the description of that state.
    """
    pass


def before_method_control(context: Experiment, 
                          configuration: Configuration = None,
                          secrets: Secrets = None, **kwargs):
    """
    before-control of the method's execution

    Called by the Chaos Toolkit before the activities of the method are
    applied.
    """
    pass


def after_method_control(context: Experiment, state: List[Run], 
                         configuration: Configuration = None,
                         secrets: Secrets = None, **kwargs):
    """
    after-control of the method's execution

    Called by the Chaos Toolkit after the activities of the method have been
    applied. The `state` is the list of activity results. See
    https://docs.chaostoolkit.org/reference/api/journal/#run for more
    information.
    """
    pass


def before_rollback_control(context: Experiment, 
                            configuration: Configuration = None,
                            secrets: Secrets = None, **kwargs):
    """
    before-control of the rollback's execution

    Called by the Chaos Toolkit before the actions of the rollback are
    applied.
    """
    pass


def after_rollback_control(context: Experiment, state: List[Run], 
                           configuration: Configuration = None,
                           secrets: Secrets = None, **kwargs):
    """
    after-control of the rollback's execution

    Called by the Chaos Toolkit after the actions of the rollback have been
    applied. The `state` is the list of actions results. See
    https://docs.chaostoolkit.org/reference/api/journal/#run for more
    information.
    """
    pass


def before_activity_control(context: Activity, 
                            configuration: Configuration = None,
                            secrets: Secrets = None, **kwargs):
    """
    before-control of the activity's execution

    Called by the Chaos Toolkit before the activity is applied.
    """
    pass


def after_activity_control(context: Activity, state: Run,  
                           configuration: Configuration = None,
                           secrets: Secrets = None, **kwargs):
    """
    after-control of the activity's execution

    Called by the Chaos Toolkit before the activity is applied. The result of
    the execution is passed as `state`. See
    https://docs.chaostoolkit.org/reference/api/journal/#run for more
    information.
    """
    pass

Use your control

Define those functions into a module that is used as a provider. For instance, assume the above definition is stored into a module chaosstuff.control, in other words a control.py module of the chaosstuff package.

The package must obviously be available to the PYTHONPATH in which the chaos runs.

Declare it in the experiment

Controls can be applied per-experiment only:

"controls": [
    {
        "name": "my-stuff",
        "provider": {
            "type": "python",
            "module": "chaosstuff.control"
        }
    }
]
controls:
  - name: my-stuff
    provider:
      type: python
      module: chaosstuff.control

Declare it in your settings

Controls can be also applied globally to all runs by declaring them in the Chaos Toolkit settings file:

controls:
    my-stuff:
        provider:
            type: python
            module: chaosstuff.control

Things to note

Unforeseen errors

The Chaos Toolkit will not let a control abort the execution of the experiment. So if an exception is raised, it will be caught by the Chaos Toolkit, logged and the execution will carry on.

Interrupting the execution

While unforeseen errors in your controls cannot stop the execution, you can interrupt the execution by raising chaoslib.exceptions.InterruptExecution from any of your control functions.

Note however, this is a harsh way to terminate the execution since, none of the rollbacks will be applied.

Here is an example:

from chaoslib.exceptions import InterruptExecution


def after_activity_control(context: Activity, state: Run,  
                           configuration: Configuration = None,
                           secrets: Secrets = None, **kwargs):
    if check_stuff(state["output"]):
        raise InterruptExecution("Well things went really bad!")

In that case, the experiment’s execution will have its status set to "interrupted" as described here.