Inverting States#
In SLS function refs present and absent are complimentary to each other, and are used to ensure that a resource (corresponding to a state) gets created or gets deleted. Sometimes it is desirable to not write two different SLS files for just creating and deleting some states. This is where SLS inversion tries to help. Command line argument --invert
can be used to invert the behaviour of SLS file. However, this is not without limitations.
Motivation#
The goal of SLS inversion is to use same SLS file to both create and delete resources as the case may be. All this can be understood with help of an example:
Assure Resource Group Present test_group:
azure.resource_management.resource_groups.present:
- resource_group_name: test_group
- parameters:
location: eastus
In the above SLS, we are creating a resource group. In the usual case to delete the above resource group we need to create a SLS file like so:
Assure Resource Group absent test_group:
azure.resource_management.resource_groups.absent:
- resource_group_name: test_group
- parameters:
location: eastus
With help of command-line parameter --invert
we can create and delte the resource group using the same SLS, like so:
Click here to see command execution details
$ tail rg_create.sls
Assure Resource Group Present test_group:
azure.resource_management.resource_groups.present:
- resource_group_name: test_group
- parameters:
location: eastus
$ idem state --output json rg_create.sls
{
"azure.resource_management.resource_groups_|-Assure Resource Group Present test_group_|-Assure Resource Group Present test_group_|-present": {
"changes": {
"new": {
"id": "/subscriptions/some-subscription/resourceGroups/test_group",
"name": "test_group",
"type": "Microsoft.Resources/resourceGroups",
"location": "eastus",
"properties": {
"provisioningState": "Succeeded"
}
}
},
"comment": "Created",
"name": "Assure Resource Group Present test_group",
"result": true,
"old_state": null,
"new_state": null,
"__run_num": 1
}
}
$ idem state --output json --invert rg_create.sls
{
"azure.resource_management.resource_groups_|-Assure Resource Group Present test_group_|-Assure Resource Group Present test_group_|-absent": {
"changes": {
"old": {
"id": "/subscriptions/some-subscription/resourceGroups/test_group",
"name": "test_group",
"type": "Microsoft.Resources/resourceGroups",
"location": "eastus",
"properties": {
"provisioningState": "Succeeded"
}
}
},
"comment": "Accepted",
"name": "Assure Resource Group Present test_group",
"result": true,
"old_state": null,
"new_state": null,
"__run_num": 1
}
}
In this manner we can reverse changes done by an existing SLS file without actually writing a separate SLS file.
State Requisite Handling#
With SLS inversion, all state requisites also get inverted, in a sense that the order of execution of states is reversed. The idea behind this approach is to execute states in an inverted SLS in the reverse order of normal SLS. For example consider the following SLS:
sleep_mid:
time.sleep:
- require:
- time: sleep_first
- duration: 1
sleep_end:
time.sleep:
- require:
- time: sleep_mid
- duration: 1
sleep_independent:
time.sleep:
- duration: 1
sleep_first:
time.sleep:
- duration: 1
Normal Run#
In a normal run (without --invert
) the order of execution will be
sleep_first, sleep_independent
sleep_mid
sleep_end
Click here to see actual execution details
$ idem state --output json invert.sls
{
"time_|-sleep_independent_|-sleep_independent_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_independent",
"result": true,
"__run_num": 1
},
"time_|-sleep_first_|-sleep_first_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_first",
"result": true,
"__run_num": 2
},
"time_|-sleep_mid_|-sleep_mid_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_mid",
"result": true,
"__run_num": 3
},
"time_|-sleep_end_|-sleep_end_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_end",
"result": true,
"__run_num": 4
}
}
Inverted Run#
With a --invert
command-line parameter the order of state execution will be:
sleep_end, sleep_independent
sleep_mid
sleep_first
Click here to see actual execution details
$ idem state --output json --invert invert.sls
{
"time_|-sleep_end_|-sleep_end_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_end",
"result": true,
"__run_num": 1
},
"time_|-sleep_independent_|-sleep_independent_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_independent",
"result": true,
"__run_num": 2
},
"time_|-sleep_mid_|-sleep_mid_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_mid",
"result": true,
"__run_num": 3
},
"time_|-sleep_first_|-sleep_first_|-sleep": {
"comment": [
"Successfully slept for 1 seconds."
],
"old_state": {},
"new_state": {},
"name": "sleep_first",
"result": true,
"__run_num": 4
}
}
Requirements#
To make SLS inversion work, all mandatory parameters required for absent and present for any given state should be present in the SLS, irrespective of actual function ref you are using. For example, the SLS file
Delete {{subnet}}:
aws.ec2.subnet.absent:
- name: {{VpcName}}
will not work with --invert
command-line parameter. Since some mandatory parameters required by present are not provided. If the parameters required by present are also provided like below, inversion will work as expected with or without command-line parameter --invert
.
Delete {{subnet}}:
aws.ec2.subnet.absent:
- name: {{VpcName}}
- vpc_id: {{VpcId}}
- cidr_block: 10.0.0.0/24
- availability_zone: us-east-1d
- tags:
- Key: Name
Value: one1
Limitations#
For some use cases, --invert
works well, but there are limitations.
Argument binding does not work
Because argument binding uses output of one state to define input of another state, it doesn’t work with SLS inversion.