Controlling files on a Salt Minion is a common operation that SaltStack does well. The basic principle is that if the file is changed on the Minion, then a state run should return it back to a known State as dictated by the Salt Master. Files can be static objects that the Master just downloads or it can be a template and dynamically populated with data from Grains and state data from the master.
Example 1 – Basic managed file state.
In this example, we download the file /etc/modprobe.d/lustre.conf to the Minion and set its ownership and permissions. The “ID” field is this example is the actual target, but we set the target name anyway with the “- name: “ key.
It is also worth noting that this example represents the old state file format which has been replaced with file.managed syntax:
/etc/modprobe.d/lustre.conf:
file:
- managed
- source: salt://roles/hpc/lnet/conf/lustre.conf
- name: /etc/modprobe.d/lustre.conf
- user: root
- group: root
- mode: 644
Example 2 – Multiple file downloads
In this example, we need to move a number of files in a directory from the Master to /opt/client/rpms on the minion, we can set the ownership but Salt will set the individual permissions based on the source file(s). We also use a variable from the pillar data, explained below:
upload-directory:
file.recurse:
- name: /opt/client/rpms
- source: salt://servers/{{ pillar['server_name'] }}/client/rpms/
- include_empty: True
- user: root
- group: root
- file_mode: keep
Pillar data – quick introduction
Its not often desirable to hardcode into a State file fixed value like a “server name”, instead we can store this data in an SLS file as YAML in the /srv/pillar directory and in the /srv/pillar/top.sls file reference ALL the pillar data for a host. There will be another post of Pillar data later.
Example 3 – Templated file download
The following example state file uses a basic “for” loop to show how a block of code can be called repetitively to download files to a client. To avoid hard coding the list of files in the state file, a pillar could be used. The immediate disadvantage is the file ownership and perms, but we could use a more complex pillar structure to hold that information as well.
{% for FILE in [‘test1.rpm’,’test2.rpm’,’dev-test3.rpm’] %}
/opt/client/{{ FILE }}:
file.managed:
– source: salt://servers/{{ pillar[‘server_name’] }}/client/{{ FILE }}
– user: root
– group: root
– mode: ‘0664’
{% endfor %}
-oOo-