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