Gestion de dépendances#
Exprimer les dépendances entre les states#
Introduction#
- Défi:
définir la causalité des éléments du système et les dépendances entre les différentes briques du système de configuration
C’est le point difficile pour décrire l’état d’un système ou d’une infrastructure
Requisites#
Salt propose des outils (appelés requisites) pour définir ces dépendances et contrôler l’ordre d’exécution des states
Les 3 principaux requisites qui permettent de déclarer des dépendances fonctionnelles entre des states sont :
require
etrequire_in
: déclaration de dépendance entre 2 stateswatch
etwatch_in
: pour s’assurer qu’un state est réévalué lors de la modification de l’état d’un autre stateprereq
etprereq_in
: pour déclarer un état nécessaire d’un autre state pour appliquer un state
Attention : la définition des states est déclarative ; cependant, l’ordre dans lequel les states apparaissent dans les fichiers est respecté.
Autres requisites#
On trouve en plus des requisites plus organisationnelles :
include
: pour pouvoir faire référence à des states déclarés dans un autre fichieruse
etuse_in
: permet de dupliquer les paramètres d’un autre stateonchanges
etonchanges_in
: pour appliquer un état lorsque l’état dont il dépend a changé et a fonctionné.onfail
etonfail_in
: pour appliquer un état lorsqu’un autre état est en échec (par exemple, point de montage des backups)order
: déclarer un numéro d’ordre (à éviter)sur le state
cmd
:unless
etonlyif
Identifiants#
Les identifiants des states doivent être uniques pour un système ciblé
La valeur de l’argument obligatoire
name
de toutes les fonctions desstate modules
est par défaut l’identifiant dustate
(lestate-id
)Il est recommandé de ne pas utiliser le
state-id
commename
par défaut, cela peut entraîner des conflits de nom (dans lesinclude
,require
, etc.)
Ceci :
vim:
pkg.installed
est équivalent à :
vim is installed:
pkg.installed:
- name: vim
Cette seconde forme est recommandée.
Require#
require
#
On peut exprimer une dépendance entre deux states à l’aide du
paramètre require
, par exemple :
vim is configured:
file.managed:
- name: /etc/vim/vimrc
- source: salt://edit/vimrc
- require:
- pkg: vim
La forme du require
est donc <statemodule>: <ID>
il ne peut donc y avoir qu’une seule fonction de state dans un
state module
qui implémente la gestion de la dépendance,<ID>
peut être l’identifiant du state ou la valeur de son paramètrename
Si on a la déclaration :
vim is installed:
pkg.installed:
- name: vim
On peut utiliser soit l’identifiant du state :
vim is configured:
file.managed:
- name: /etc/vim/vimrc
- require:
- pkg: vim is installed
soit la name
passé en argument :
vim is configured:
file.managed:
- name: /etc/vim/vimrc
- require:
- pkg: vim
Il est possible de faire un require
sur un ficher .sls
au
complet (tous les états déclarés dans un fichier sls
) :
include:
- other
local:
pkg.installed:
- require:
- sls: other
require_in
#
Relation inverse de require
{% if not grains['custom_machine'] %}
vim is installed:
pkg.installed:
- name: vim
- require_in: vim is configured
{% endif %}
vim is configured:
file.managed:
- name: /etc/vim/vimrc
- source: salt://edit/vimrc
Permet de rajouter des dépendances quand l’accès aux fichiers dépendants
n’est pas possible ou pour des dépendances sur des include
par exemple.
À utiliser pour des dépendances optionnelles (blocs if
et for
notamment) afin
d’améliorer la lisibilité du code.
L’exemple précédant écrit avec un require
serait :
{% if not grains['custom_machine'] %}
vim is installed:
pkg.installed:
- name: vim
{% endif %}
vim is configured:
file.managed:
- name: /etc/vim/vimrc
- source: salt://edit/vimrc
{% if not grains['custom_machine'] %}
- require:
- pkg: vim
{% endif %}
Ce qui est moins lisible.
Watch#
watch
#
Permet de définir un comportement supplémentaire d’un state en fonction des changements qui surviennent sur un autre state
Ce « comportement supplémentaire » dépend du state module
sur lequel
ce paramètre watch
est utilisé :
pour que watch fonctionne, il faut que la fonction
mod_watch
soit définie dans le module sur lequel on met unwatch
sinon, watch se comporte comme require
les
state modules
qui définissent la fonctionmod_watch
sont :cmd
service
supervisord
mount
etcd
dockerio
etdockerng
tomcat
watch
- service
#
Pour states.service
:
Principe : quand un fichier de configuration d’un service est modifié, et on souhaite le recharger.
Salt essaye alors les fonctions suivantes :
service.reload
service.force_reload
service.full_restart
service.restart
service.start
/etc/stuff/config:
- file.managed:
- source: salt://stuff/configfile
stuffdaemon:
- service.running:
- watch:
- file: /etc/stuff/config
watch
- cmd
#
Principe : quand l’application d’un state cmd.run
renvoit True
avec la liste des choses qui ont été modifiées, l’utilisation de
watch
permet de réagir à cette modification de l’état du système :
pour utiliser un watch dans un state
cmd
, il faut utilisercmd.wait
plutôt quecmd.run
:
/usr/local/bin/postinstall.sh:
cmd.wait:
- watch:
- pkg: mycustompkg
file.managed:
- source: salt://utils/scripts/postinstall.sh
mycustompkg:
pkg.installed:
- require:
- file: /usr/local/bin/postinstall.sh
watch_in
#
Relation inverse de
watch
Comme dans le cas des
require_in
, lewatch_in
est à utiliser pour les dépendances optionnelles
Prereq#
prereq
#
Définit le state actuel comme pré-requis pour effectuer des modifications dans un autre state.
Utilise test=True
dans le state auquel on fait référence pour
évaluer si des changements vont être appliqués par l’état testé
Intérêt :
évite d’effectuer des opérations de préparation inutiles automatiquement
permet de scripter des opérations plus complexes avec des
sls
.
prereq
- exemple#
Arrêter un service pendant une mise à jour d’un site uniquement si cette mise à jour fait quelque chose.
apache_stopped:
service.dead:
- name: apache2
- prereq:
- file: data_files
data_files:
file.recurse:
- name: /var/www/site/data
- source: salt://var/www/sitedata/
apache_running:
service.running:
- name: apache2
- watch:
- file: data_files
prereq_in
#
Utilisé par des blocs optionnels (cf.
require_in
etwatch_in
)
Visualisation#
Un projet tiers permet de visualiser en GraphViz les dépendances : ceralena/salt-state-graph
Autres#
onchanges
#
devpi service:
file.managed:
- name: /lib/systemd/system/devpi.service
- source: salt://devpi/conf/devpi.service
cmd.run:
- name: systemctl daemon-reload
- onchanges:
- file: /lib/systemd/system/devpi.service
onfail
#
mount remote data:
mount.mounted:
- name: /mnt/data
- device: storage.example.org:/data
- fstype: nfs
mount backup data:
mount.mounted:
- name: /mnt/data
- device: backup.storage.example.org:/data
- fstype: nfs
- onfail:
- mount: mount remote data
use
#
Utiliser les mêmes paramètres qu’une autre déclaration
/etc/foo.conf:
file.managed:
- source: salt://foo.conf
- template: jinja
- user: apache
- group: apache
/etc/bar.conf:
file.managed:
- source: salt://bar.conf
- use:
- file: /etc/foo.conf
Attention:
use
n’hérite pas desrequire
,watch
etprereq
il n’est pas possible de « chaîner » les
use
unless
- cmd.run
#
Exécuter un état sauf si une commande est vraie
bonne pratique : lancer les tests avant d’installer un logiciel ou un service
mirror site:
cmd.run:
name: wget --mirror [snip]
unless: cat /var/run/mirror-in-progress
onlyif
- cmd.run
#
Définition inverse de
unless
Exécuter un état seulement si une commande définie est vraie
mirror site:
cmd.run:
name: wget --mirror [snip]
onlyif: wget http://example.org
Dépendances entre machines#
orchestrate
#
Exemple, dans /srv/salt/orchestration/webapp.sls
:
install_postgres: # en premier les machines db*
salt.state:
- tgt: 'db*'
- sls:
- postgres.server
load_database_dump:
salt.function:
- tgt: 'db*'
- name: cmd.run
- arg:
- pg_restore dump
install_webserver:
salt.state:
- tgt: 'web*'
- highstate: True
puis on lance depuis la console:
# salt-run state.orchestrate orchestration.webapp
Le runner orchestrate
permet d’orchestrer des états et des
exécutions de fonctions entre plusieurs minions
utilise les fonctions définies dans le state module
salt
[1] :salt.function
: exécuter une fonction d’un module d’exécutionsalt.state
: exécuter un état salt (sls), dont highstatesalt.runner
: exécuter unrunner
coté master (pas de tgt)salt.wait_for_event
: observer le bus d’événement et attendre un événementsalt.wheel
: exécuter une fonctionwheel
coté master (module de configuration du master)
les minions sont ciblés sont spécifiés par l’argument
tgt
overstate
(deprecié)#
overstate.sls
permet de définir des dépendances entre sls et de les appliquer à différents minionsil s’agit du passage de la notion de dépendance présente dans les sls au niveau des machines
au lieu de travailler au sein d’un seul minion, on gère des dépendances entre minions, par exemple :
salt-run state.over
[...]
salt-run state.over env='dev' alternative_overstate.sls
[...]
le fichier par défaut pour definir des overstates est recherché à la racine et s’appelle
overstate.sls
on peut spécifier d’autres fichiers overstate si on le souhaite et les appeler explicitement depuis le master
Exemple:
mysql: #en premier les machines db*
match: 'db*'
sls:
- mysql.server
- drbd
webservers: #puis les serveurs web*
match: 'web*'
require:
- mysql
all: #si tout marche, le reste
match: '*'
require:
- mysql
- webservers