Group Plugins#

Group plugins can organize and manipulate the return data of an Idem run before it is rendered.

Finding Group Plugins#

Use idem doc to list all the available group plugins:

$ idem doc group | grep -o "^group.\w*"

You can also use jq to list plugins next to their doc strings:

$ idem doc group --output=json | jq -r '. | keys[] as $k | "\($k): \(.[$k].doc)"'

At the time of writing, with no extra plugins installed, this is the result of that command:

group.duration.apply: Sort the output by the total seconds of the state's run time
group.init.apply: Apply all group plugins specified in config
group.number.apply: Sort the data by run number
group.omit_noop.apply: Remove states that reported success without changes
group.sort.apply: Reorganize the data by sorting by each state's unique tag

Using Group Plugins#

Group plugins are specified in a single string and are separated by a pipe. Each group plugin will be run in the order that it is defined.

Group plugins can be specified on the cli with the --group flag.

$ idem state my_state.sls --group="number|omit_noop"

Group plugins can also be specified in the idem config.

# idem.cfg
idem:
  group: number|omit_noop

Creating a Group Plugin#

First create a directory at my_project_root/my_provider/group. In your project’s conf.py, extend the Idem namespace with your group directory.

# my_project_root/my_provider/conf.py
DYNE = {"group": ["group"]}

Now create a plugin in your source directory.

The plugin simply needs to implement the apply function. This function receives the hub, and data arguments. These will be passed into the function.

data contains the full results of a state run. Here are the contents of data for a run containing a single state:

{
    "resource_ref_|-state_block_name_|-state_name_|-function": {
        "tag": "resource_ref_|-state_block_name_|-state_name_|-function",
        "name": "state_name",
        "changes": {},
        "new_state": {},
        "old_state": {},
        "comment": None,
        "rerun_data": None,
        "result": True,
        "esm_tag": "resource_ref_|-state_block_name_|-state_name_|-",
        "__run_num": 1,
        "start_time": "2022-08-15 09:39:33.608291",
        "total_seconds": 0.001207,
        "sls_meta": {"SLS": {}, "ID_DECS": {}},
    },
}

This is what a basic group plugin looks like:

# my_project_root/my_provider/group/my_plugin.py
from typing import Any
from typing import Dict


def apply(hub, data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Re-organize/filter the state runtime results from "data"
    """
    # initialize an ordered dictionary for the return (All dictionaries are ordered after python 3.8)
    ret = {}
    # iterate over the state return data in the order you want to add it to the return
    for tag in data:
        # retrieve the result of a single state
        state_ret = data[tag]
        # Break the state tag into it's component parts
        comps = tag.split("_|-")
        state = comps[0]
        id_ = comps[1]
        fun = comps[3]
        # "result" is True if the state ran successfully, otherwise it is False
        result = state_ret.get("result")
        # Any comment(s) from the running state
        comment = state_ret.get("comment")
        # An empty dictionary if there were no changes, else a comparison of "new" and "old" state of the resource
        changes = state_ret.get("changes", {})
        # The state of the resource before the function ran
        old_state = state_ret.get("old_state", {})
        # The state of the resource after the function ran
        new_state = state_ret.get("new_state", {})

        # omit this state ret from the return data based on any of the previous information
        if not True:
            continue

        # Copy the state ret from the input data to the return data
        ret[tag] = data[tag]

    return ret