When managing services with SaltStack, we often need to ensure clean environments before deploying new configurations. A common scenario is removing old configuration files (like *.conf in /etc/supervisord/conf.d/) before setting up new supervisor services.
The attempted solution using file.absent
doesn't work because:
/etc/supervisor/conf.d/*:
file.absent
This fails because file.absent
operates on complete paths, not patterns. SaltStack doesn't expand glob patterns in this context.
Method 1: Using file.directory with clean=True
The proper way to clear a directory while keeping the directory itself:
clear_supervisor_configs:
file.directory:
- name: /etc/supervisord/conf.d/
- clean: True
- require_in:
- file: /etc/supervisord/conf.d/new_service.conf
Method 2: Pattern-based Removal with cmd.run
For more control over which files to remove:
remove_old_configs:
cmd.run:
- name: rm -f /etc/supervisord/conf.d/*.conf
- onlyif: test -n "$(ls /etc/supervisord/conf.d/*.conf 2>/dev/null)"
Method 3: Advanced Globbing with file.absent
SaltStack's more recent versions support this pattern:
{% for file in salt['file.find']('/etc/supervisord/conf.d', name='*.conf') %}
remove_{{ file|replace('/', '_') }}:
file.absent:
- name: {{ file }}
{% endfor %}
When clearing directories in SaltStack:
- Always test with
salt-call state.apply test=True
first - Consider adding
- require
or- require_in
to ensure proper ordering - For production systems, implement a backup mechanism
Here's a complete solution with safety checks:
backup_old_configs:
cmd.run:
- name: |
mkdir -p /var/backups/supervisor/$(date +%Y%m%d)
cp /etc/supervisord/conf.d/*.conf /var/backups/supervisor/$(date +%Y%m%d)/
- onlyif: test -n "$(ls /etc/supervisord/conf.d/*.conf 2>/dev/null)"
clear_config_directory:
file.directory:
- name: /etc/supervisord/conf.d/
- clean: True
- require:
- cmd: backup_old_configs
deploy_new_configs:
file.managed:
- name: /etc/supervisord/conf.d/new_service.conf
- source: salt://supervisor/files/new_service.conf
- require:
- file: clear_config_directory
When trying to clear configuration files before deployment, many SaltStack users first attempt the file.absent
state. However, this approach has limitations when dealing with wildcard patterns:
/etc/supervisor/conf.d/*.conf:
file.absent
This state declaration won't work because file.absent
expects explicit paths, not glob patterns. The state simply checks if the literal path "/etc/supervisor/conf.d/*.conf" exists as a file (which it doesn't) and does nothing.
Solution 1: Using cmd.run with find
For a reliable cleanup operation before deploying new configurations:
clean_supervisor_configs:
cmd.run:
- name: find /etc/supervisor/conf.d/ -name "*.conf" -delete
- onlyif: test -d /etc/supervisor/conf.d/
The onlyif
clause ensures the command only runs if the directory exists, preventing errors.
Solution 2: SaltStack file.glob_remove
A more Salt-native approach using the file.glob_remove
execution module:
remove_old_configs:
module.run:
- name: file.glob_remove
- path: /etc/supervisor/conf.d/*.conf
Solution 3: Combining with requisites
When this cleanup needs to happen before other states:
clean_configs:
module.run:
- name: file.glob_remove
- path: /etc/supervisor/conf.d/*.conf
deploy_new_configs:
file.managed:
- name: /etc/supervisor/conf.d/myapp.conf
- source: salt://supervisor/files/myapp.conf
- require:
- clean_configs
For more complex scenarios where you need to:
- Preserve certain files while deleting others
- Handle permission issues
- Log deleted files
Consider this enhanced version:
selective_cleanup:
module.run:
- name: file.find
- path: /etc/supervisor/conf.d/
- name: '*.conf'
- notname: 'keep_me.conf'
- delete: True
- print: name