Core Commands
salt - Primary command for executing modules on minions from the master:
salt [options] '<target>' <function> [arguments]
Example: salt '*' test.ping
salt-run - Execute runnner modules on the master:
salt-run manage.status # View all minion statuses
salt-run manage.down # Show offline minions
salt-run manage.up # Show online minions
salt-key - Manage authentication keys:
salt-key -L # List all minion keys
salt-key -a <minion-id> # Accept specific key
salt-key -d <minion-id> # Delete specific key
salt-key -A # Accept all pending keys
salt-key -D # Delete all keys
salt-call - Execute modules locally on minion:
salt-call test.ping # Local ping test
salt-call cmd.run 'ifconfig' # Execute command locally
salt-cp - Distribute files to minions:
salt-cp '*' source.txt /tmp/destination.txt
User Execution Permissions
Access Control Lists (ACL)
Configure in master configuration file:
client_acl:
monitor:
- 'test*':
- 'test.*'
dev:
- 'service.*'
sa:
- '.*'
After configuration, restart master and set proper permissions:
chmod +r /etc/salt/master
chmod +x /var/run/salt
chmod +x /var/cache/salt
External Authentication
Configure in master:
external_auth:
pam:
monitor:
- 'test':
- test.
sa:
- .*
Use tokens to avoid repeated password prompts:
salt -T -a pam '*' test.ping
Targeting Minions
Targeting Methods
Globbing (default):
salt 'web*' test.ping
Regular Expressions:
salt -E 'web1-(prod|dev)' test.ping
List:
salt -L 'server1,server2,server3' test.ping
Grains:
salt -G 'os:CentOS' test.ping
salt '*' grains.items # View all grains
salt '*' grains.ls # List grain keys
salt '*' grains.item num_cpus # Get specific grain
Node Groups:
Define in master configuration:
nodegroups:
web_servers: 'L@web1,web2 or web3*'
db_servers: 'G@os:CentOS and db*'
Usage:
salt -N web_servers test.ping
Compound Targeting:
salt -C 'G@os:CentOS and L@192.168.1.10,192.168.1.11' test.ping
Remote Execution
Basic syntax for remote command execution:
salt '<target>' <function> [arguments]
Examples:
salt '*' service.restart httpd
salt '*' pkg.install vim
salt '*' cmd.run 'uptime'
Multi-Master Configuration
- Install Salt Master on additional server
- Copy master keys from primary master: ```
scp /etc/salt/pki/master/master.pem newmaster:/etc/salt/pki/master/
- Start new master service
- Configure minions to connect to multiple masters: ```
master:
- master1.example.com
- master2.example.com
- Restart minion service
- Accept keys on new master
Pillar Data Management
Pillar stores sensitive and minion-specific data on the master.
Viewing Pillar Data
salt '*' pillar.items
salt '*' pillar.item <key>
salt '*' pillar.get <key>:<subkey>
Creating Pillar Data
1. Define pillar roots (default: /srv/pillar):
mkdir /srv/pillar
cd /srv/pillar
2. Create pillar data file:
vim /srv/pillar/apache.sls
apache_version: '2.4.41'
document_root: '/var/www/html'
3. Create top file:
vim /srv/pillar/top.sls
base:
'*':
- apache
4. Refresh pillar data:
salt '*' saltutil.refresh_pillar
Grains System
Grains provide static information about minions.
Viewing Grains
salt '*' grains.items
salt '*' grains.item osrelease
salt '*' grains.get fqdn
Custom Grains
Create custom grainss module:
mkdir /srv/salt/_grains
vim /srv/salt/_grains/custom.py
def server_role():
grains = {}
grains['server_role'] = 'webserver'
return grains
Sync to minions:
salt '*' saltutil.sync_grains
State Management
States define the desired configuration of systems.
State File Example
apache:
pkg.installed:
- name: httpd
service.running:
- name: httpd
- require:
- pkg: httpd
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- user: root
- group: root
- mode: 644
Top File Configuration
base:
'*':
- apache
'web*':
- webserver
- database
Executing States
salt '*' state.sls apache
salt '*' state.highstate
Rendering Systems
Salt supports multiple renderers for state files.
Jinja Templates
apache:
pkg.installed:
{% if grains['os'] == 'RedHat' %}
- name: httpd
{% elif grains['os'] == 'Ubuntu' %}
- name: apache2
{% endif %}
service.running:
- name: httpd
{% if grains['os'] == 'RedHat' %}
- name: httpd
{% else %}
- name: apache2
{% endif %}
Python Renderer
#!py
def run():
config = {}
if grains['os_family'] == 'RedHat':
config['httpd'] = {
'pkg': ['installed'],
'service': ['running']
}
return config
Requisite System
Define dependencies between states.
Require/Require In
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- require_in:
- service: httpd
httpd:
service.running:
- require:
- pkg: httpd
Watch/Watch In
httpd:
service.running:
- watch:
- file: /etc/httpd/conf/httpd.conf
/etc/httpd/conf/httpd.conf:
file.managed:
- source: salt://apache/httpd.conf
- watch_in:
- service: httpd
Environment Management
Configure multiple environments in master:
file_roots:
base:
- /srv/salt/prod
dev:
- /srv/salt/dev
- /srv/salt/prod
test:
- /srv/salt/test
- /srv/salt/prod
Scheduled Tasks
Master Schedules
schedule:
overstate:
function: state.over
minutes: 30
hours: 2
Minion Schedules
schedule:
highstate:
function: state.highstate
minutes: 60
backup:
function: cmd.run
args:
- rsync -av /data/ backup@server:/backup/
hours: 6
Event System and Reacotrs
Reactors Configuration
Configure in master:
reactor:
- 'salt/minion/*/start':
- /srv/reactor/start.sls
- 'custom/event/*':
- /srv/reactor/custom.sls
Reactor Example
{% if data['id'] == 'web01' %}
apply_config:
local.state.apply:
- tgt: {{ data['id'] }}
- arg:
- webserver
{% endif %}
Salt Mine
Mine gathers and stores data from minions for sharing.
Configuration
Configure in minion:
mine_functions:
network.interfaces: []
disk.usage: []
mine_interval: 60
Usage
salt '*' mine_get '*' network.interfaces
salt 'web01' mine_get 'db*' disk.usage
Salt SSH
Agentless Salt execution via SSH.
Roster Configuration
web01:
host: 192.168.1.10
user: root
passwd: password
port: 22
sudo: True
web02:
host: 192.168.1.11
user: deploy
priv: /path/to/private/key
sudo: True
Usage
salt-ssh '*' test.ping
salt-ssh '*' -r 'ls -l /tmp'
salt-ssh '*' state.sls apache
Returners
Direct minion return data to various storage systems.
Custom Returner Example
def __virtual__():
return 'custom_log'
def returner(ret):
import json
with open('/var/log/salt/returns.log', 'a') as f:
f.write(json.dumps(ret) + '\n')
Usage
salt '*' test.ping --return custom_log
Extending SaltStack
Custom Execution Module
def custom_function(param):
"""
Custom function example
"""
cmd = 'custom_command --option {0}'.format(param)
return __salt__['cmd.run'](cmd)
Custom State Module
def managed(name, source=None):
ret = {'name': name,
'changes': {},
'result': False,
'comment': '',
'duration': ''}
if source:
# File management logic here
ret['result'] = True
ret['comment'] = 'File managed successfully'
return ret
Job Management
Viewing Active Jobs
salt-run jobs.active
salt '*' saltutil.running
Job Lookup
salt '*' test.ping -v # Show JID
salt-run jobs.lookup_jid <jid>
Terminating Jobs
salt '*' saltutil.term_job <jid>
salt '*' saltutil.kill_job <jid>
File Backup and Restore
Configuration
/tmp/test.conf:
file.managed:
- source: salt://files/test.conf
- backup: minion
Managing Backups
salt '*' file.list_backups /tmp/test.conf
salt '*' file.restore_backup /tmp/test.conf <backup_id>
salt '*' file.delete_backup /tmp/test.conf <backup_id>
Master Configuration Options
interface: 0.0.0.0
publish_port: 4505
ret_port: 4506
user: root
timeout: 5
keep_jobs: 24
job_cache: True
file_roots:
base:
- /srv/salt
pillar_roots:
base:
- /srv/pillar
log_level: warning
Minion Configuration Options
master: salt.example.com
master_port: 4506
id: minion01
user: root
cache_jobs: False
backup_mode: minion
renderer: yaml_jinja
log_level: info
tcp_keepalive: True