# Provisioning
# Ansible
Command | Meaning | default | SaltStack equivalent |
---|---|---|---|
--check | Dry run | no dry run | test=True |
-b, --become | run operations with become | no password prompting | |
-K, --ask-become-pass | ask for privilege escalation password | ||
--become-method=BECOME_METHOD | privilege escalation method to use valid choices: [ sudo su pbrun pfexec doas dzdo ksu runas pmrun enable machinectl sudo | sudo | |
--become-user=BECOME_USER | run operations as this user | root |
Example | meaning |
---|---|
ansible-playbook playbook.yml --user=b.dauphin --become-method=su -b -K | su b.dauphin + password prompting |
ansible-playbook playbook.yml --check --diff --limit 1.2.3.4 | Dry run + show only diff + limit inventory to host 1.2.3.4 |
# Examples
cd inventory
ls *.yml | xargs -I % ansible --user=baptiste -i % all -m shell -a 'grep 8.8.8.8 /etc/resolv.conf || echo MISCONFIGURED'
2
Specify python interpreter path
ansible 1.2.3.4 -m ping -e 'ansible_python_interpreter=/usr/bin/python3'
list available variables
ansible 10.10.10.10 -m setup
get specific fact
ansible 10.10.10.10 -m setup -a 'filter=ansible_python_version'
Playbook start at a specific task
ansible-playbook --start-at-task="Gather Networks Facts into Variable"
ansible webservers -m service -a "name=httpd state=restarted"
ansible all -m ping -u user1 --private-key /home/baptiste/.ssh/id_rsa
2
enable usage of operations like < > | &
the remote system has to got the package python-apt
apt install python-apt
- debug: var=ansible_facts
2
# start only specific task
ansible-playbook --tags "docker_login"
# Debug ansible playbook
# print a specific var. Warning does not print vars in group_vars nor host_vars
[...]
msg: "{{ lookup('vars', ansible_dns) }}"
[...]
2
3
[...]
- name: Gather Networks Facts into Variable
setup:
register: setup
- name: Debug Set Facts
debug:
var: setup.ansible_facts.ansible_python_version
2
3
4
5
6
7
8
# Variables
# Inside Playbook
---
- hosts: webservers
vars:
syslog_protocol_lvl_4: udp
syslog_port: 514
ansible_python_interpreter: /bin/python
ansible_ssh_user: root
2
3
4
5
6
7
8
# Cli override
ansible-playbook release.yml --extra-vars '{"version":"1.23.45","other_variable":"foo"}'
ansible-playbook arcade.yml --extra-vars '{"pacman":"mrs","ghosts":["inky","pinky","clyde","sue"]}'
2
override playbook-defined variables (keep your playbook unmodified)
ansible-playbook lvm.yml --extra-vars "host=es_data_group remote_user=b.dauphin" -i ../inventory/es_data_staging.yml
2
Full doc of passing-variables-on-the-command-lineopen in new window
# Precedence
Where should I put a variable ? Here is the order of precedence from least to greatest (the last listed variables winning prioritization):
- command line values (eg “-u user”)
- role defaults [1]
- inventory file or script group vars [2]
- inventory group_vars/all [3]
- playbook group_vars/all [3]
- inventory group_vars/* [3]
- playbook group_vars/* [3]
- inventory file or script host vars [2]
- inventory host_vars/* [3]
- playbook host_vars/* [3]
- host facts / cached set_facts [4]
- play vars
- play vars_prompt
- play vars_files
- role vars (defined in role/vars/main.yml)
- block vars (only for tasks in block)
- task vars (only for the task)
- include_vars
- set_facts / registered vars
- role (and include_role) params
- include params
- extra vars (always win precedence)
# Lookup plugin
You can load data from various sources like : k8s
, ini
, file
, vault
, mongoDB
, env var
, etcd
To get list of available lists of lookup plugins, you can use below command: –
ansible-doc -t lookup -l
Example
ansible_become_pass: "{{ lookup('hashi_vault', 'secret=secret/data/path/to/secret'+ ':data url=https://vault.example.com validate_certs=true cacert=/etc/ssl/certs/ca-certificates.crt').root}}"
2
3
# SaltStack
# Key management
--list=$ARG | definition |
---|---|
pre,un,unaccepted | list unaccepted/unsigned keys. |
acc or accepted | list accepted/signed keys. |
rej or rejected | list rejected keys |
den or denied | list denied keys |
all | list all above keys |
# Targeting
salt -S 192.168.40.20 test.version
salt -S 192.168.40.0/24 test.version
2
Compound match
salt -C 'S@10.0.0.0/24 and G@os:Debian' test.version
salt -C '( G@environment:staging or G@environment:production ) and G@soft:redis*' test.ping
2
full docopen in new windowCompound matchersopen in new window
# Various useful module
salt '*' network.ip_addrs
salt '*' cmd.run
salt '*' state.Apply
salt '*' test.ping
salt '*' test.version
salt '*' grains.get
salt '*' grains.item
salt '*' grains.items
salt '*' grains.ls
2
3
4
5
6
7
8
9
# Diff
Diff between 2 servers
salt-run survey.diff '*' cmd.run "ls /home"
# Saltutils
Signal the minion to refresh the pillar data.
salt '*' saltutil.refresh_pillar
synchronizes custom modules, states, beacons, grains, returners, output modules, renderers, and utils.
salt '*' saltutil.sync_all
Forcibly removes all caches on a minion. WARNING: The safest way to clear a minion cache is by first stopping the minion and then deleting the cache files before restarting it.
soft way
salt '*' saltutil.clear_cache
sure way
systemctl stop salt-minion \
&& rm -rf /var/cache/salt/minion/ \
&& systemctl start salt-minion
2
3
# Grains
# Common
- SSDs
- biosreleasedate
- biosversion
- cpu_flags
- cpu_model
- cpuarch
- disks
- dns
- domain
- fqdn
- fqdn_ip4
- fqdn_ip6
- gid
- gpus
- groupname
- host
- hwaddr_interfaces
- id
- init
- ip4_gw
- ip4_interfaces
- ip6_gw
- ip6_interfaces
- ip_gw
- ip_interfaces
- ipv4
- ipv6
- kernel
- kernelrelease
- kernelversion
- locale_info
- localhost
- lsb_distrib_codename
- lsb_distrib_id
- machine_id
- manufacturer
- master
- mdadm
- mem_total
- nodename
- num_cpus
- num_gpus
- os
- os_family
- osarch
- oscodename
- osfinger
- osfullname
- osmajorrelease
- osrelease
- osrelease_info
- path
- pid
- productname
- ps
- pythonexecutable
- pythonpath
- pythonversion
- saltpath
- saltversion
- saltversioninfo
- selinux
- serialnumber
- server_id
- shell
- swap_total
- systemd
- uid
- username
- uuid
- virtual
- zfs_feature_flags
- zfs_support
- zmqversion
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# grains containing 'os'
os:
Debian
os_family:
Debian
osarch:
amd64
oscodename:
stretch
osfinger:
Debian-9
osfullname:
Debian
osmajorrelease:
9
osrelease:
9.5
osrelease_info:
- 9
- 5
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Upgrade Salt-Minion
# State format
Upgrade Salt-Minion:
cmd.run:
- name: |
exec 0>&- # close stdin
exec 1>&- # close stdout
exec 2>&- # close stderr
nohup /bin/sh -c 'salt-call --local pkg.install salt-minion && salt-call --local service.restart salt-minion' &
- onlyif: "[[ $(salt-call --local pkg.upgrade_available salt-minion 2>&1) == *'True'* ]]"
2
3
4
5
6
7
8
# Bash script format
Upgrade salt-minion bash scriptopen in new window
# Useful exemple
# Netcat
salt -C "minion.local or minion2.local" \
> cmd.run "docker run debian /bin/bash -c 'http_proxy=http://10.100.100.100:1598 apt update ; http_proxy=http://10.100.100.100:1598 apt install netcat -y ; nc -zvn 10.3.3.3 3306' | grep open"
minion.local:
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
debconf: delaying package configuration, since apt-utils is not installed
(UNKNOWN) [10.3.3.3] 3306 (?) open
minion2.local:
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.
debconf: delaying package configuration, since apt-utils is not installed
(UNKNOWN) [10.3.3.3] 3306 (?) open
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# MySQL connexion
Will print you the GRANTS for the user
echo "enter your password" ; read -s password ; \
salt "*" \
cmd.run "docker pull imega/mysql-client ; docker run --rm imega/mysql-client mysql --host=10.10.10.10 --user=b.dauphin --password=$password --database=db1 --execute='SHOW GRANTS FOR CURRENT_USER();'" \
env='{"http_proxy": "http://10.10.10.10:9999"}'
2
3
4
# Events
Salt provides a runner that displays events in real-time as they are received on the Salt master.
salt-run state.event pretty=True
# Jinja2
# Filter list
https://www.tailored.cloud/devops/how-to-filter-and-map-lists-in-ansible/
# Playing with empty lines
{% %}
{%- %}
{% -%}
{%- -%}
2
3
4
(By default) add an empty line before jinja rendering
and add one after
{% set site_url = 'www.' + domain %}
remove the empty line before jinja rendering
and add one after
{%- set site_url = 'www.' + domain %}
add the empty line before jinja rendering
and remove one after
{% set site_url = 'www.' + domain -%}
remove the empty line before jinja rendering
and remove one after
{%- set site_url = 'www.' + domain -%}
# Test variable existence
{% if min_verbose_level is defined
and min_verbose_level %}
and level({{ min_verbose_level }} .. emerg);
{% endif %}
2
3
4
# Templating
Jinja2 is a rendering layer applied before
the actual python
(i.e. saltstack instruction) is interpreted.
{% set ipaddr = grains['fqdn_ip4'][0] %}
{% if (key | regex_match('.*dyn.company.tld.*', ignorecase=True)) != None %}
2
{% set syslog_java_application =
pillar.get('syslog_java_application', {}) %}
{% if syslog_java_application %}
{% set syslog_module_name =
syslog_java_application.get('name') %}
{% set types =
syslog_java_application.get('types') %}
{% set log_folder_path =
syslog_java_application.get('log_folder_path') %}
{% set log_file_name_prefix =
syslog_java_application.get('log_file_name_prefix') %}
{% endif %}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% for type in types %}
{% set source_name = syslog_module_name ~ '_' ~ type %}
{% set file_full_path = log_folder_path ~ '/' ~ log_file_name_prefix ~ type ~ '.log' %}
{% set program_override = syslog_module_name ~ '_' ~ type %}
syslog-ng app_function_{{ type }} configuration:
file.managed:
- name: /etc/syslog-ng/conf.d/{{ syslog_module_name }}_{{ type }}.conf
- source: salt://template.tmpl
- template: jinja
- user: root
- group: root
- mode: 644
- watch_in:
- service: syslog-ng
- context:
name: {{ source_name }}
file_full_path: {{ file_full_path }}
program_override: {{ program_override }}
{% endfor %}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# JSON parsing
# json_query_example.sls
{% set services = '
{"services": [
{"name": "http", "host": "1.2.3.4", "port": 80},
{"name": "smtp", "host": "1.2.3.5", "port": 25},
{"name": "ssh", "host": "1.2.3.6", "port": 22}
]}' | load_json %}
{% set ports = services | json_query("services[].port") %}
2
3
4
5
6
7
8
9