Incremental Settings for Ansible Values
Many existing Ansible modules allow for incrementally changing the state of
the system or of the underlying managed object. For example, when you use the
sysctl module, you do not provide every single sysctl setting describing
the entire state of the kernel settings. Instead, you provide a single
setting which incrementally updates the state of all of the sysctl
settings, by adding, modifying, or removing a single value.
- name: modify a single kernel setting
sysctl:
name: some_setting
value: 123 # to add/replace the value
or
- name: modify a single kernel setting
sysctl:
name: some_setting
state: absent # to remove the value
Many roles in the System Roles project need to follow the usual pattern of
module interfaces and allow specifying incremental changes instead of the
complete state to be able to be safely used multiple times in a playbook
without the later invocation clobbering the result of the previous invocation,
and to preserve previous state of the managed systems. We had a need to
generalize the usual approach of modules to lists of settings for role
parameters. We based our approach on
Kubernetes JSON strategic merge,
and reuse of the Ansible state keyword. We use this to manage objects which
are represented by a list of dict objects.
Removing list items with state: absent
This is the case where you want to remove some of the values from the managed
object. Use state: absent in the dict value to remove the item named by
name. For example, if you are using widget_manager to manage a list of
widgets:
widget_manager:
- name: widget_a
value: 111
- name: widget_b
state: absent
- name: widget_c
state: absent
This will change the state of widget widget_a to have the value of 111,
and will remove widgets widget_b and widget_c from being managed by the
managed object. NOTE: the behavior of state: absent depends on what the
underlying implementation is actually doing. If a widget is a physical
object in the system, this might mean that the implementation will remove the
object (like the file module will remove the file with state: absent).
This might mean that the implementation will remove the specified object from
the list of objects being managed (like the sysctl module, which will remove
the parameter from the /etc/sysctl.conf file, but the actual value of the
parameter will not revert to its original value until after a reboot).
Extending the usage, some scalar parameters could be a target of removal with
state: absent. Here is an example. Assuming a scalar parameter
kernel_settings_systemd_cpu_affinity has a string value “1,3,5,7”.
kernel_settings_systemd_cpu_affinity: "1,3,5,7"
To remove the value, use the dict value {"state": "absent"}.
kernel_settings_systemd_cpu_affinity:
state: absent
The kernel_settings already implemented the feature. For the implementation
details, we recommend to see the role.
Replacing an entire list of items with the given values with previous: replaced
This is the case where you want to remove all of the existing values in the
managed object and replace those values with the given values. Use
previous: replaced as one of the items in the list of values (preferably
the first value in the list). For example, using widget_manager parameters:
widget_manager:
- previous: replaced
- name: widget_a
value: 785592
- name: widget_b
value: 111111
- name: widget_c
value: 222222
This will remove any existing settings and replace them with the settings given.
Removing all of the settings with state: empty
This is the case where you want to remove all of the existing values in the
managed object. For example, if you want to remove all of the
widget_manager parameters:
widget_manager:
state: empty
This will remove all of the widget_manager parameters. NOTE: This does
exactly the same thing as - previous: replaced, but is a shorter, more
readable version. That is, using state: empty as above is equivalent to
this:
widget_manager:
- previous: replaced