Paul's Internet Landfill/ 2019/ Editing Files in Saltstack

Editing Files in Saltstack

As much as I ought to put up tech blogs as I work through projects, I can't keep up. So I tend to tech blog only when I discover something I couldn't find on the Internet beforehand. Today's entry is kind of like that and kind of not.

I have been working on configuring a server using the Saltstack configuration management system. A big part of this involves setting configuration files. Often these edits are done using the salt.states.file module. There are many methods provided. Which should you use?

In order of preference, here are the strategies I use when configuring a package:

I do not think there are any other good options. file.append is terrible because it is not robust -- if you change one byte of the stuff you appended, Salt will re-append the snippet entirely. Maybe there are other good options, but I have not found them.

Editing Lines in a File

For some (probably stupid) reason, I decided I needed to edit the /etc/exim4/update-exim4.conf.conf file line by line. My strategy was as follows:

Here is the dictionary I used in my edit. The first element of each tuple is the configuration option, and the second is the value:

{% set configlines = [('dc_eximconfig_configtype', 'satellite',),
                      ('dc_other_hostnames', '' ),
                      ('dc_use_split_config', 'true'),
                      ('dc_readhost', grains['fqdn']),
                      ('dc_smarthost', pillar['exim4']['smarthost']),
                      ('dc_hide_mailname', 'true'),
                     ] %}

Now you can loop through each of these elements and make a change. Note that each edit needs its own Salt ID, which is where conf[0] comes in:

{% for conf in configlines %}
/etc/exim4/update-conf-{{ conf[0] }}:
  file.line:
    - name: /etc/exim4/update-exim4.conf.conf
    - match: {{ conf[0] }}=
    - content: {{ conf[0] }}='{{ conf[1] }}'
    - mode: replace
    - backup: False
    - require:
      - pkg: exim4
{% endfor %}

The match directive looks for the line to edit. The content one sets the option. The replace actually does the change. Note that if the line is commented out then this will leave the line commented.

It is very important to note that you should only change ONE line at a time using file.line. Trying to change multiple lines will work, but is very fragile in the same way file.append is. In that situation you should use file.blockreplace instead.