via package APT
root@disi-dellat:~# apt update root@disi-dellat:~# apt install ansible Les paquets suivants ont été installés automatiquement et ne sont plus nécessaires : libfwupdplugin1 libsysmetrics1 Veuillez utiliser « apt autoremove » pour les supprimer. Les paquets supplémentaires suivants seront installés : ieee-data python3-argcomplete python3-dnspython python3-jmespath python3-kerberos python3-libcloud python3-netaddr python3-ntlm-auth python3-requests-kerberos python3-requests-ntlm python3-selinux python3-winrm Paquets suggérés : cowsay sshpass ipython3 python-netaddr-docs Les NOUVEAUX paquets suivants seront installés : ansible ieee-data python3-argcomplete python3-dnspython python3-jmespath python3-kerberos python3-libcloud python3-netaddr python3-ntlm-auth python3-requests-kerberos python3-requests-ntlm python3-selinux python3-winrm 0 mis à jour, 13 nouvellement installés, 0 à enlever et 3 non mis à jour. Il est nécessaire de prendre 9 379 ko dans les archives. Après cette opération, 88,6 Mo d'espace disque supplémentaires seront utilisés. Souhaitez-vous continuer ? [O/n] O ... Paramétrage de python3-netaddr (0.7.19-3ubuntu1) ... Paramétrage de python3-winrm (0.3.0-2) ... Paramétrage de ansible (2.9.6+dfsg-1) ...
nous allons travailler avec un user nommé ans qui sera utiliser pour notre gestion ansible sur le server-node on créé ce user avec un uid specifique ici 1033
root@disi-dellat:~# adduser ans --uid 1033 $ su - ans Mot de passe : ans@disi-dellat:~$ ans@disi-dellat:~$ ansible --version ansible 2.9.6 config file = /etc/ansible/ansible.cfg configured module search path = ['/home/ans/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules'] ansible python module location = /usr/lib/python3/dist-packages/ansible executable location = /usr/bin/ansible python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
apres l'avoir créé sur notre noeud serveur , on créé aussi sur notre client exemple :
root@PrecisT36:~# adduser ans --uid=1033 Adding user `ans' ... Adding new group `ans' (1033) ... Adding new user `ans' (1033) with group `ans' ... Creating home directory `/home/ans' ... Copying files from `/etc/skel' ... New password:
generation d'une clé SSH pour l'utilisateur ans avec nom specifique id_rsa_ansible_sn (ansible-server-node) et passphrass assoviée
ans@disi-dellat:~$ ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/home/ans/.ssh/id_rsa): /home/ans/.ssh/id_rsa_ansible_sn Created directory '/home/ans/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/ans/.ssh/id_rsa_ansible_sn Your public key has been saved in /home/ans/.ssh/id_rsa_ansible_sn.pub The key fingerprint is: SHA256:Jlw3secret9oGC1dIQ ans@disi-dellat The key's randomart image is: +---[RSA 3072]----+ | o.. *| | ... | +----[SHA256]-----+
on recopie notre clée public ssh vers le noeud client (nodept3)
ans@disi-dellat:~$ ssh-copy-id ans@nodept3 /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/ans/.ssh/id_rsa_ansible_sn.pub" The authenticity of host 'nodept3 (192.168.1.68)' can't be established. ECDSA key fingerprint is SHA256:vsbLgBSECRETy5I684I. Are you sure you want to continue connecting (yes/no/[fingerprint])? yes /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys ans@nodept3's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'ans@nodept3'"
generation d'un fichier .ssh/config afin de specifier quelle clé/ID utiliser vers quel node
ans@disi-dellat:~$ cat .ssh/config host nodept3 HostName nodept3 IdentityFile ~/.ssh/id_rsa_ansible_sn User ans
maintenant le ssh vers ce noeud client se fait sans password, mais avec passPhrase toutefois :
ans@disi-dellat:~$ ssh 'ans@nodept3' Enter passphrase for key '/home/ans/.ssh/id_rsa_ansible_sn': upAnSibleSSHdo ans@PrecisT36:~$
on va lancer un agent ssh pour stocker l'association passPhrase-clé afin d'eviter de saisir la passPhrse a chaque lancement
ans@disi-dellat:~$ eval `ssh-agent` Agent pid 296069 ans@disi-dellat:~$ ssh-add -l The agent has no identities. ans@disi-dellat:~$ ssh-add ~/.ssh/id_rsa_ansible_sn ans@disi-dellat:~$ ssh-add -l 3072 SHA256:Jlw3+M8dcv1SECRETC1dIQ ans@disi-dellat(RSA)
demonstration de ssh entre notre node-server et le client (nodept3 = PrecisT36)
ans@disi-dellat:~$ ssh nodept3 ans@PrecisT36:~$
si par megarde on rencontre un soucis d'usage d'openssl sur la clé ssh (retrait de la passphrase par exemple) , il est alors utile de forcer une format RSA/PEM sur notre clé initialement au format OPENSSH
ans@disi-dellat:~$ file ~/.ssh/id_rsa_ansible_sn /home/ans/.ssh/id_rsa_ansible_sn: OpenSSH private key ans@disi-dellat:~$ ssh-keygen -p -f ~/.ssh/id_rsa_ansible_sn -m pem Enter old passphrase: Key has comment 'ans@disi-dellat' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase. ans@disi-dellat:~$ file ~/.ssh/id_rsa_ansible_sn /home/ans/.ssh/id_rsa_ansible_sn: PEM RSA private key
on peux pour backup retirer la passphrase (et stocker cette clé privée non protégée ailleurs)
ans@disi-dellat:~$ cp ~/.ssh/id_rsa_ansible_sn ~/.ssh/id_rsa_ansible_sn-cpp ans@disi-dellat:~$ openssl rsa -in ~/.ssh/id_rsa_ansible_sn-cpp -out ~/.ssh/id_rsa_ansible_sn-cpp-nop Enter pass phrase for /home/ans/.ssh/id_rsa_ansible_sn-cpp: writing RSA key
premier test ansible depuis le node-server vers le client avec un simple “ping/pong”
ans@disi-dellat:~$ ansible -i "nodept3," all -m ping nodept3 | SUCCESS => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false, "ping": "pong" }
on demande a faire du ansible avec un inventaire contenant que “nodept3” avec le group all et le module ping
le fichier de configuration d'ansible peut etre à plusieurs endroit avec une precedence de preference d'acces qui suis cet ordre
les differentes sections de parametrage par defaut
ans@disi-dellat:~$ grep "^\[" /etc/ansible/ansible.cfg [defaults] [inventory] [privilege_escalation] [paramiko_connection] [ssh_connection] [persistent_connection] [accelerate] [selinux] [colors] [diff]
la commande ansible-config dispose des parametres view et list pour voir repectivement les valeurs postionnées dans le ansible.cfg utilisé et la list de tous les parametres que l'on va pouvoir positionner
ans@disi-dellat:~$ ansible-config view # config file for ansible -- https://ansible.com/ # =============================================== # nearly all parameters can be overridden in ansible-playbook # or with command line flags. ansible will read ANSIBLE_CONFIG, # ansible.cfg in the current working directory, .ansible.cfg in # the home directory or /etc/ansible/ansible.cfg, whichever it # finds first [defaults] # some basic default values... #inventory = /etc/ansible/hosts #library = /usr/share/my_modules/ #module_utils = /usr/share/my_module_utils/ #remote_tmp = ~/.ansible/tmp #local_tmp = ~/.ansible/tmp #plugin_filters_cfg = /etc/ansible/plugin_filters.yml #forks = 5 #poll_interval = 15 #sudo_user = root #ask_sudo_pass = True #ask_pass = True #transport = smart #remote_port = 22 #module_lang = C #module_set_locale = False ...
ans@disi-dellat:~$ ansible-config list ACTION_WARNINGS: default: true description: - By default Ansible will issue a warning when received from a task action (module or action plugin) - These warnings can be silenced by adjusting this setting to False. env: - name: ANSIBLE_ACTION_WARNINGS ini: - key: action_warnings section: defaults name: Toggle action warnings type: boolean version_added: '2.5' AGNOSTIC_BECOME_PROMPT: default: true description: Display an agnostic become prompt instead of displaying a prompt containing the command line supplied become method env: - name: ANSIBLE_AGNOSTIC_BECOME_PROMPT ini: - key: agnostic_become_prompt - ...
sans pipelining
avec pipelining
ans@disi-dellat:~/ansible$ vim ansible.cfg #pipelining = False pipelining = True
ans@disi-dellat:~/ansible$ vim ansible.cfg [ssh_connection] # ssh arguments to use # Leaving off ControlPersist will result in poor performance, so use # paramiko on older platforms rather than removing it, -C controls compression use #ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey
partager plusieurs sessions pour une meme connexion, faire persister la connexion 60s et preciser directement qu'on va faire de l'auth par publickey plutot que d'essayer toutes les methodes .
parallelisme de gestion de nodes, par exemple faire 10 clients à la fois
ans@disi-dellat:~/ansible$ vim ansible.cfg [defaults] forks = 10
a chaque session, le server node va recuperer des info pour positionner les variables propres au client, son nom, son OS, ses @IP, interfaces reseau etc …
ans@disi-dellat:~/ansible$ vim ansible.cfg [defaults] # smart - gather by default, but don't regather if already gathered # implicit - gather by default, turn off with gather_facts: False # explicit - do not gather by default, must say gather_facts: True #gathering = implicit gathering = implicit
autres optimations pour grosse structures ⇒ mitogen : https://mitogen.networkgenomics.com/ansible_detailed.html
voire faire du pull avec des clients ansible sur localhost qui vont chercher sur une depot git la config et la runner vian ansible-pull un a un quand bon leur semble
la commande ansible en CLI est plutot utilisée pour des tests, petite taches, deblocage de situation etc … en prod on va plutot jouer des playbook yaml avec ansible-playbook .
exemple de lancement en mode ultra verbose avec le user distant jehan, utilisation d'un ssh-python (-c paramiko (cf paramiko.org) ) car autrement on reçois un FAILED! ⇒ “to use the 'ssh' connection type with passwords, you must install the sshpass program” et demande de prompt du password via -k pour appel final du module ping :
ans@disi-dellat:~/ansible$ ansible -vvv -i "nodept3," all -u jehan -c paramiko -k -m ping
exemple de lancement de commande
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -m command -a uptime --one-line nodept3 | CHANGED | rc=0 | (stdout) 22:30:08 up 5:32, 1 user, load average: 0,01, 0,04, 0,08
exemple de lancement de commande via un shell qui permet des commandes plus complexe integrant des pipe
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -c paramiko -m shell -a "ps -auwx | grep jehan | wc -l" -u jehan -k -K SSH password: BECOME password[defaults to SSH password]: nodept3 | CHANGED | rc=0 >> 105
utiliser ansible en distant sans utiliser python, par exemple pour une machine qui ne l'a pas encore on pourra faire un install python ! on utilise alors le module raw avec l'elevation de privilege + demande pass privilege (-K) :
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -b -K -m raw -a "apt install -y python3"
plutot que d'utiliser le module raw puis apt install , il sera preferable d'utiliser le module apt et ses multiples options : https://docs.ansible.com/ansible/latest/collections/ansible/builtin/apt_module.html
ans@disi-dellat:~/ansible$ ansible -vv -i "nodept3," all -b -K -m apt -a "name=wireshark state=latest"
positionner l'etat d'un service via le module service
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -b -K -m service -a "name=apache2 state=stopped"
simple copy de fichier
ans@disi-dellat:~/ansible$ vim filetest.txt ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -b -K -m copy -a "src=filetest.txt dest=/tmp/filetest-ans.txt" BECOME password: nodept3 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python3" }, "changed": true, "checksum": "df800445bb74b4abb144b3f9bf03f90aa9618f4c", "dest": "/tmp/filetest-ans.txt", "gid": 0, "group": "root", "md5sum": "f61d358bbdd6a9bd2e93322023a4e29d", "mode": "0644", "owner": "root", "size": 14, "src": "/home/ans/.ansible/tmp/ansible-tmp-1660512072.1366317-239729049960172/source", "state": "file", "uid": 0 }
recuperer un fichier depuis l'hote distant avec option d'ecrassement si existant localement (flat=yes)
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -b -K -m fetch -a "src=/tmp/filetest-ans.txt dest=/tmp/filetest-ans-fetch.txt flat=yes" BECOME password: nodept3 | CHANGED => { "changed": true, "checksum": "b0265654b260f04c119005b7a293389cdf566856", "dest": "/tmp/filetest-ans-fetch.txt", "md5sum": "dbd6c447a5077dc690557df11f9ada60", "remote_checksum": "b0265654b260f04c119005b7a293389cdf566856", "remote_md5sum": null } ans@disi-dellat:~/ansible$ cat /tmp/filetest-ans-fetch.txt hello ansible welcome back
recuperer tous les gather facts (informations sur l'hote distant)
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -m setup nodept3 | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.1.8" ], "ansible_all_ipv6_addresses": [ ... "ansible_os_family": "Debian", "ansible_pkg_mgr": "apt", ...
filtrer sur la distribution
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -m setup -a "filter=ansible_distribution" nodept3 | SUCCESS => { "ansible_facts": { "ansible_distribution": "Ubuntu", "discovered_interpreter_python": "/usr/bin/python3" }, "changed": false }
recensement de la liste des machines et variables attenantes avec les repartoires hosts_vars et group_vars . Son organisation est importante, on va pouvoir y “typer” (ranger par role, web, db etc ) la liste des nodes a gerer . Deux types d'object
l'inventory peut-etre en type ini (plat) ou yaml (structure en arbre), il peut-etre aussi en format json pour beneficier d'outils de gestion automatique.
on peut utiliser des patterns .
le groupe all est parent de tous exemple de definition de group contenant des hosts (format ini) :
[parent1] srv1 [enfant1] srv2 srv3 [enfant2] srv4 [enfant3] srv5
puis definition d'une hierarchie
[parent1:children] enfant1 enfant2 [enfant2:children] enfant3
all: children: parent1: hosts: srv1: children: enfant1: hosts: srv2: srv3: enfant2: hosts: srv4: children: enfant3: hosts: srv5:
on peut imbriquer des groupes dans un groupe, ici parent2 au meme niveau que parent1
all: children: parent1: parent2: hosts: srv1: parent2: hosts: srv6: srv7:
exemple au lieu de mettre srv6: et srv7: on met srv[6:7]:
references
variables d'inventaires
partons sur cet exemple d'inventaire yml :
all: children: common: children: webserver: hosts: node[2:3]: vars: var1: "webserver" dbserver: hosts: node4: node5: var1: "node5" vars: var1: "dbserver" monitoring: children: webserver: dbserver:
utilisation du module debug pour afficher une variable positionnée en ligne de commande
ans@disi-dellat:~/ansible$ ansible -i "nodept3," all -e "var1=helloA" -m debug -a 'msg={{ var1 }}' nodept3 | SUCCESS => { "msg": "helloA" }
utilisation de notre 00_inventory.yml
ans@disi-dellat:~/ansible$ ansible -i 00_inventory.yml all -m debug -a 'msg={{ var1 }}' [WARNING]: Skipping unexpected key (monitoring) in group (common), only "vars", "children" and "hosts" are valid node2 | SUCCESS => { "msg": "webserver" } node4 | SUCCESS => { "msg": "dbserver" } node3 | SUCCESS => { "msg": "webserver" } node5 | SUCCESS => { "msg": "node5" }
on voit que var1 est bien surchargée pour node5 dans le group dbserver
il est preferable d'un point de vue organisation de créer une arborescence dans le filesystem pour tenir compte de la hierarchie des variable plutot que de tout mettre dans l'inventaire .
ans@disi-dellat:~/ansible$ mkdir group_vars ans@disi-dellat:~/ansible$ vim group_vars/webserver.yml ans@disi-dellat:~/ansible$ cat group_vars/webserver.yml var1: "gp_webserver" ans@disi-dellat:~/ansible$ cp group_vars/webserver.yml group_vars/dbserver.yml ans@disi-dellat:~/ansible$ vim group_vars/dbserver.yml ans@disi-dellat:~/ansible$ cat group_vars/dbserver.yml var1: "gp_dbserver"
on a donc cette arborescence
ans@disi-dellat:~/ansible$ tree . ├── 00_inventory.yml ├── 01_inventory.yml ├── ansible.cfg ├── filetest.txt ├── group_vars │ ├── dbserver.yml │ └── webserver.yml └── inventory.yml 1 directory, 7 files
on adapte notre inventory en retirant les vars de group maintenant definis dans l'arborescence de FS
ans@disi-dellat:~/ansible$ cat 01_inventory.yml all: children: common: children: webserver: hosts: node[2:3]: dbserver: hosts: node4: node5: var1: "node5"
on relance le test des vars, il donne le meme resultat
ans@disi-dellat:~/ansible$ ansible -i 01_inventory.yml all -m debug -a 'msg={{ var1 }}' node4 | SUCCESS => { "msg": "gp_dbserver" } node5 | SUCCESS => { "msg": "node5" } node2 | SUCCESS => { "msg": "gp_webserver" } node3 | SUCCESS => { "msg": "gp_webserver" }
on peut ranger encore plus finement et en anticipant l'usage de fichiers “vaulter” comme ceci
ans@disi-dellat:~/ansible$ mkdir group_vars/webserver ans@disi-dellat:~/ansible$ mv group_vars/webserver.yml group_vars/webserver/variables.yml ans@disi-dellat:~/ansible$ touch group_vars/webserver/vault.yml ans@disi-dellat:~/ansible$ mkdir group_vars/dbserver ans@disi-dellat:~/ansible$ mv group_vars/dbserver.yml group_vars/dbserver/variables.yml ans@disi-dellat:~/ansible$ tree . ├── 00_inventory.yml ├── 01_inventory.yml ├── ansible.cfg ├── filetest.txt ├── group_vars │ ├── dbserver │ │ └── variables.yml │ └── webserver │ ├── variables.yml │ └── vault.yml └── inventory.yml 3 directories, 8 files
on peut aussi extraire la variable de host (node5) de l'inventaire pour en faire une gestion par l'arborescence
ans@disi-dellat:~/ansible$ mkdir -p host_vars/node5 ans@disi-dellat:~/ansible$ vim host_vars/node5/variables.yml ans@disi-dellat:~/ansible$ cat host_vars/node5/variables.yml var1: "node5" ans@disi-dellat:~/ansible$ vim 01_inventory.yml ans@disi-dellat:~/ansible$ ans@disi-dellat:~/ansible$ ansible -i 01_inventory.yml all -m debug -a 'msg={{ var1 }}' node3 | SUCCESS => { "msg": "gp_webserver" } node2 | SUCCESS => { "msg": "gp_webserver" } node5 | SUCCESS => { "msg": "node5" } node4 | SUCCESS => { "msg": "gp_dbserver" }
on créé une variable pour all pour l'exemple
ans@disi-dellat:~/ansible$ mkdir group_vars/all ans@disi-dellat:~/ansible$ vim group_vars/all/variables.yml ans@disi-dellat:~/ansible$ cat group_vars/all/variables.yml var1: "all" ans@disi-dellat:~/ansible$ tail -4 01_inventory.yml node5: outcommon: hosts: node6: ans@disi-dellat:~/ansible$ ans@disi-dellat:~/ansible$ ansible -i 01_inventory.yml all -m debug -a 'msg={{ var1 }}' node6 | SUCCESS => { "msg": "all" } node2 | SUCCESS => { "msg": "gp_webserver" } node3 | SUCCESS => { "msg": "gp_webserver" } node4 | SUCCESS => { "msg": "gp_dbserver" } node5 | SUCCESS => { "msg": "node5" }
afficher en txt l'arborescence de l'invetory, hosts, groups, vars
ans@disi-dellat:~/ansible$ ansible-inventory -i 01_inventory.yml --list { "_meta": { "hostvars": { "node2": { "var1": "gp_webserver" }, "node3": { "var1": "gp_webserver" }, "node4": { "var1": "gp_dbserver" }, "node5": { "var1": "node5" }, "node6": { "var1": "all" } } }, "all": { "children": [ "common", "outcommon", "ungrouped" ] }, "common": { "children": [ "dbserver", "webserver" ] }, "dbserver": { "hosts": [ "node4", "node5" ] }, "outcommon": { "hosts": [ "node6" ] }, "webserver": { "hosts": [ "node2", "node3" ] } }
ou plus lisible
ans@disi-dellat:~/ansible$ ansible-inventory -i 01_inventory.yml --graph --vars @all: |--@common: | |--@dbserver: | | |--node4 | | | |--{var1 = gp_dbserver} | | |--node5 | | | |--{var1 = node5} | | |--{var1 = gp_dbserver} | |--@webserver: | | |--node2 | | | |--{var1 = gp_webserver} | | |--node3 | | | |--{var1 = gp_webserver} | | |--{var1 = gp_webserver} |--@outcommon: | |--node6 | | |--{var1 = all} |--@ungrouped: |--{var1 = all}
enfin une vrai version graphique de l'inventaire en installant au prealable le necessaire :
root@disi-dellat:~# apt install python3-pip root@disi-dellat:~# pip3 install ansible-inventory-grapher root@disi-dellat:~# apt install graphviz graphicsmagick-imagemagick-compat
on peut lancer la serie de commandes
ans@disi-dellat:~/ansible$ ansible-inventory-grapher -i 01_inventory.yml all | dot -Tpng | display png:-
un fichier qui declanche les actions (tasks) , articuler l'inventory et les roles (ensemble de taches/variables) . Il peut aussi disposer lui meme d'actions mais a eviter .
la syntaxe YAML des playbook et primordiale
ans@disi-dellat:~/ansible$ cat 0_playbook.yml --- - name: Home_Playbook hosts: all remote_user: ans tasks: - name: j_debug debug: msg: "my var1 {{ var1 }}"
il y a des erreurs sur les nodes non UP/existant (car appel de hosts: all !) , c'est normal ici .
ans@disi-dellat:~/ansible$ ansible-playbook -i 00_inventory.yml 0_playbook.yml [WARNING]: Skipping unexpected key (monitoring) in group (common), only "vars", "children" and "hosts" are valid PLAY [Home_Playbook] ******************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** Thursday 18 August 2022 19:19:47 +0200 (0:00:00.016) 0:00:00.016 ******* [WARNING]: Unhandled error in Python interpreter discovery for host node4: Failed to connect to the host via ssh: ssh: Could not resolve hostname node4: Temporary failure in name resolution ok: [node3] TASK [j_debug] ************************************************************************************************** Thursday 18 August 2022 19:19:48 +0200 (0:00:00.867) 0:00:00.884 ******* ok: [node3] => { "msg": "my var1 gp_webserver" } PLAY RECAP ****************************************************************************************************** node2 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0 node3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 node4 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0 node5 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0 Thursday 18 August 2022 19:19:48 +0200 (0:00:00.038) 0:00:00.922 ******* =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------ 0.87s j_debug -------------------------------------------------------------------------------------------------- 0
gestion de fichiers et repertoires
simple check de connexion avec ping
ans@disi-dellat:~/ansible$ cat 02_playbook_file.yml --- - name: J_Playbook_File hosts: node3 tasks: - name: check_cnx ping:
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans 02_playbook_file.yml PLAY [J_Playbook_File] ****************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** Friday 19 August 2022 10:26:58 +0200 (0:00:00.016) 0:00:00.016 ********* ok: [node3] TASK [check_cnx] ************************************************************************************************ Friday 19 August 2022 10:26:59 +0200 (0:00:00.850) 0:00:00.867 ********* ok: [node3] PLAY RECAP ****************************************************************************************************** node3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Friday 19 August 2022 10:26:59 +0200 (0:00:00.229) 0:00:01.096 ********* =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------ 0.85s check_cnx ------------------------------------------------------------------------------------------------ 0
creation d'un directory avec les droit root, necessité de monté de privilege ( become et -K )
ans@disi-dellat:~/ansible$ cat 02_playbook_file.yml --- - name: J_Playbook_File hosts: node3 become: yes tasks: - name: check_cnx ping: - name: create_directory file: path: "/tmp/ansdir" state: directory owner: root
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 02_playbook_file.yml BECOME password: PLAY [J_Playbook_File] ****************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** Friday 19 August 2022 10:33:13 +0200 (0:00:00.017) 0:00:00.017 ********* ok: [node3] TASK [check_cnx] ************************************************************************************************ Friday 19 August 2022 10:33:14 +0200 (0:00:00.868) 0:00:00.885 ********* ok: [node3] TASK [create_directory] ***************************************************************************************** Friday 19 August 2022 10:33:14 +0200 (0:00:00.326) 0:00:01.212 ********* changed: [node3] PLAY RECAP ****************************************************************************************************** node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Friday 19 August 2022 10:33:15 +0200 (0:00:00.252) 0:00:01.464 ********* =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------ 0.87s check_cnx ------------------------------------------------------------------------------------------------ 0.33s create_directory ----------------------------------------------------------------------------------------- 0.25s
jehan@node3:/tmp$ ls -ld ansdir/ drwxr-xr-x 2 root root 4096 août 19 10:33 ansdir/
creation de fichier avec touch (file fait un check de presence)
- name: create_file file: path: "/tmp/ansdir/file1" state: touch owner: root group: ans mode: 0755
le premiere fois que je joue un playbook, les actions se fonts , report “changed” (creation fichier, lien, repertoire …) , au 2eme run si c'est deja fait, ansible ne fait rien a part un report “ok” ⇒ comparer la situation qui est decrite dans le playbook avec la situation d'arrivée .L'indempotence peut-etre jouée manuellement avec “changed when” .
autre notion ⇒ statefull / stateless
l'idempotence c'est l'existence strictement de l'objet, tout ce qui est decrit doit exister ou ne pas exister, mais doit etre décrit .
Statefull ⇒ tout ce qui est decrit doit exister et tout ce qui n'est pas decrit et dont j'ai connaissance qui doit exister ne doit plus exister .
en statefull avec terraform par exemple , si je créé une VM , une DB d'etat (state) contient cet etat, et donc si je joue sur des variables de cette VM plus tard, terraform sait qu'il existe cette VM . Avec Ansible il n'y a pas d'état, il ne sais pas que le VM existe, il ne peut tient pas de registre des actions réalisées .
state present/absent ⇒ creation, destruction
ans@disi-dellat:~/ansible$ cat 03_playbook_user.yml --- - name: J_Playbook_User hosts: node3 become: yes tasks: - name: create_user_joe user: name: joe state: present uid: 1041 groups: sudo password: "{{ 'password' | password_hash('sha512') }}"
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 03_playbook_user.yml BECOME password: ... Friday 19 August 2022 13:59:41 +0200 (0:00:00.016) 0:00:00.016 ********* ok: [node3] TASK [create_user_joe] ****************************************************************************************** Friday 19 August 2022 13:59:42 +0200 (0:00:00.846) 0:00:00.863 ********* changed: [node3] PLAY RECAP ****************************************************************************************************** node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Friday 19 August 2022 13:59:43 +0200 (0:00:01.089) 0:00:01.953 ********* =============================================================================== create_user_joe ------------------------------------------------------------------------------------------ 1.09s Gathering Facts ------------------------------------------------------------------------------------------ 0.85s
jehan@node3:/tmp$ id joe uid=1041(joe) gid=1041(joe) groups=1041(joe),27(sudo)
pour voir les details systems de ce qui a été fait on ajoute un register de notre user joe avec un debug sur cette variable :
ans@disi-dellat:~/ansible$ cat 03_playbook_user.yml --- - name: J_Playbook_User hosts: node3 become: yes tasks: - name: create_user_joe user: name: joe state: present uid: 1041 groups: sudo password: "{{ 'password' | password_hash('sha512') }}" register: __user_joe - name: debug_user debug: var: __user_joe
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 03_playbook_user.yml BECOME password: ... TASK [create_user_joe] ****************************************************************************************** Friday 19 August 2022 16:13:18 +0200 (0:00:01.530) 0:00:01.547 ********* changed: [node3] TASK [debug_user] *********************************************************************************************** Friday 19 August 2022 16:13:19 +0200 (0:00:00.539) 0:00:02.087 ********* ok: [node3] => { "__user_joe": { "append": false, "changed": true, "comment": "", "failed": false, "group": 1041, "groups": "sudo", "home": "/home/joe", "move_home": false, "name": "joe", "password": "NOT_LOGGING_PASSWORD", "shell": "/bin/sh", "state": "present", "uid": 1041 } } PLAY RECAP ****************************************************************************************************** node3 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Friday 19 August 2022 16:13:19 +0200 (0:00:00.039) 0:00:02.126 ********* =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------ 1.53s create_user_joe ------------------------------------------------------------------------------------------ 0.54s debug_user ----------------------------------------------------------------------------------------------- 0.04s
si on souhaite afficher des info sur nos actions, on peut utiliser le module stat sur un fichier par exemple, mais l'affichage des “stat” ne donne rien par defaut, il faut faire un register de l'output pour pouvoir le remonter sur notre server-node source du playbook .
ans@disi-dellat:~/ansible$ cat 04_playbook_stat_reg.yml --- - name: J_Playbook_Stat_Reg hosts: node3 become: yes tasks: - name: create_file file: path: "/tmp/ansdir/file2" state: touch owner: root group: ans mode: 0755 - name: stat_file stat: path: "/tmp/ansdir/file2" register: __stat_file2 - name: display debug: var: __stat_file2
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 04_playbook_stat_reg.yml BECOME password: PLAY [J_Playbook_Stat_Reg] ************************************************************************************** TASK [Gathering Facts] ****************************************************************************************** Saturday 20 August 2022 10:03:05 +0200 (0:00:00.021) 0:00:00.021 ******* ok: [node3] TASK [create_file] ********************************************************************************************** Saturday 20 August 2022 10:03:07 +0200 (0:00:01.235) 0:00:01.256 ******* changed: [node3] TASK [stat_file] ************************************************************************************************ Saturday 20 August 2022 10:03:07 +0200 (0:00:00.277) 0:00:01.533 ******* ok: [node3] TASK [display] ************************************************************************************************** Saturday 20 August 2022 10:03:07 +0200 (0:00:00.278) 0:00:01.812 ******* ok: [node3] => { "__stat_file2": { "changed": false, "failed": false, "stat": { "atime": 1660982587.677271, "attr_flags": "e", "attributes": [ "extents" ], "block_size": 4096, "blocks": 0, "charset": "binary", "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "ctime": 1660982587.677271, "dev": 2053, "device_type": 0, "executable": true, "exists": true, "gid": 1033, "gr_name": "ans", "inode": 262175, "isblk": false, "ischr": false, "isdir": false, "isfifo": false, "isgid": false, "islnk": false, "isreg": true, "issock": false, "isuid": false, "mimetype": "inode/x-empty", "mode": "0755", "mtime": 1660982587.677271, "nlink": 1, "path": "/tmp/ansdir/file2", "pw_name": "root", "readable": true, "rgrp": true, "roth": true, "rusr": true, "size": 0, "uid": 0, "version": "3306389664", "wgrp": false, "woth": false, "writeable": true, "wusr": true, "xgrp": true, "xoth": true, "xusr": true } } } PLAY RECAP ****************************************************************************************************** node3 : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Saturday 20 August 2022 10:03:07 +0200 (0:00:00.042) 0:00:01.854 ******* =============================================================================== Gathering Facts ------------------------------------------------------------------------------------------ 1.24s stat_file ------------------------------------------------------------------------------------------------ 0.28s create_file ---------------------------------------------------------------------------------------------- 0.28s display -------------------------------------------------------------------------------------------------- 0.04s
plus specifiquement si on veux filtrer uniquement sur le retour de stat d'existence du fichier , on utilise dans le module debug un msg sur la variable stat_file2 dans son dictionnaire il y a une clé stat qui a elle meme une clée exists qui prend la valeur true :
- name: display debug: msg: "Fichier exist : {{ __stat_file2.stat.exists }}"
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 04_playbook_stat_reg.yml TASK [display] ************************************************************************************************** Saturday 20 August 2022 10:18:19 +0200 (0:00:00.281) 0:00:01.823 ******* ok: [node3] => { "msg": "Fichier exist : True" }
avec cette condition d'existence, on peut maintenat faire une autre action sur le base de ce test, exemple ici on créé un directory si (when) la variable valeur exists = true
- name: creation conditionnelle du subDir file: path: /tmp/ansdir2 state: directory when: __stat_file2.stat.exists == True
TASK [display] ************************************************************************************************** Saturday 20 August 2022 10:27:42 +0200 (0:00:00.294) 0:00:01.512 ******* ok: [node3] => { "msg": "Fichier exist : True" } TASK [creation conditionnelle du subDir] ************************************************************************ Saturday 20 August 2022 10:27:42 +0200 (0:00:00.047) 0:00:01.559 ******* changed: [node3] PLAY RECAP ****************************************************************************************************** node3 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
la plus classique avec with_items qui est une liste a base de dictionnaire
creation de 3 repertoires
ans@disi-dellat:~/ansible$ cat 021_playbook_dir.yml --- - name: J_Playbook_File_Dir hosts: node3 become: yes tasks: - name: create_x_dir file: path: "/tmp/ansdir/{{ item }}" state: directory recurse: yes owner: root with_items: - ansdirA - ansdirB - ansdirC
TASK [create_x_dir] ********************************************************************************************* Saturday 20 August 2022 10:45:11 +0200 (0:00:01.403) 0:00:01.420 ******* changed: [node3] => (item=ansdirA) changed: [node3] => (item=ansdirB) changed: [node3] => (item=ansdirC)
on peut aussi utiliser les items sous forme de dictionnaire de valeur
tasks: - name: create_x_dir file: path: "/tmp/ansdir/{{ item.dir }}/{{ item.fichier }}" state: directory recurse: yes owner: root with_items: - { dir: ansdirA, fichier: "file1.txt" } - { dir: ansdirB, fichier: "file1.txt" } - { dir: ansdirC, fichier: "file1.txt" }
TASK [create_x_dir] ********************************************************************************************* Saturday 20 August 2022 10:52:27 +0200 (0:00:00.901) 0:00:00.918 ******* changed: [node3] => (item={'dir': 'ansdirA', 'fichier': 'file1.txt'}) changed: [node3] => (item={'dir': 'ansdirB', 'fichier': 'file1.txt'}) changed: [node3] => (item={'dir': 'ansdirC', 'fichier': 'file1.txt'}) PLAY RECAP ****************************************************************************************************** node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
d'un point de vue organisation, il vaut mieux sortir ces variables du playbook pour les mettre dans le group_vars
ans@disi-dellat:~/ansible$ cat group_vars/all/variables.yml mydict: - { dir: ansdirA, fichier: "file1.txt" } - { dir: ansdirB, fichier: "file1.txt" } - { dir: ansdirC, fichier: "file1.txt" }
avec dans le playbook un appel a ce dictionnaire
with_items: {{ mydict }}
installer un paquet , plein d'options existe, cf ref ci-dessus .
ans@disi-dellat:~/ansible$ cat 05_playbook_apt.yml --- - name: J_Playbook_Apt hosts: node3 become: yes tasks: - name: gestion_apt apt: name: tree state: latest update_cache: yes cache_valid_time: 300
le state: present est moins risqué en terme d'updates involontaires .
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 05_playbook_apt.yml ... TASK [gestion_apt] ********************************************************************************************** Saturday 20 August 2022 11:29:43 +0200 (0:00:01.394) 0:00:01.412 ******* changed: [node3] PLAY RECAP ****************************************************************************************************** node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Saturday 20 August 2022 11:29:58 +0200 (0:00:15.744) 0:00:17.156 ******* =============================================================================== gestion_apt --------------------------------------------------------------------------------------------- 15.74s Gathering Facts ------------------------------------------------------------------------------------------ 1.39s
supression totale
- name: gestion_apt apt: name: tree state: absent purge: yes autoremove: yes
on demande un reboot sur la base de la presence d'un fichier
ans@disi-dellat:~/ansible$ cat 06_playbook_reboot.yml --- - name: J_Playbook_File_Reboot hosts: node3 become: yes tasks: - name: create_fileR file: path: "/tmp/fileR" state: touch - name: stat_fileR stat: path: "/tmp/fileR" register: __stat_fileR - name: reboot_node reboot: msg: "Reboot par Ansible" connect_timeout: 5 reboot_timeout: 300 pre_reboot_delay: 0 post_reboot_delay: 50 test_command: uptime when: __stat_fileR.stat.exists - name: reboot_ok file: path: "/tmp/rebootOK" state: touch
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 06_playbook_reboot.yml BECOME password: PLAY [J_Playbook_File_Reboot] *********************************************************************** TASK [Gathering Facts] ****************************************************************************** Saturday 20 August 2022 11:54:11 +0200 (0:00:00.017) 0:00:00.017 ******* ok: [node3] TASK [create_fileR] ********************************************************************************* Saturday 20 August 2022 11:54:12 +0200 (0:00:00.859) 0:00:00.876 ******* changed: [node3] TASK [stat_fileR] *********************************************************************************** Saturday 20 August 2022 11:54:12 +0200 (0:00:00.294) 0:00:01.171 ******* ok: [node3] TASK [reboot_node] ********************************************************************************** Saturday 20 August 2022 11:54:12 +0200 (0:00:00.301) 0:00:01.473 ******* changed: [node3] TASK [reboot_ok] ************************************************************************************ Saturday 20 August 2022 11:55:25 +0200 (0:01:13.094) 0:01:14.567 ******* changed: [node3] PLAY RECAP ****************************************************************************************** node3 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Saturday 20 August 2022 11:55:26 +0200 (0:00:00.861) 0:01:15.429 ******* =============================================================================== reboot_node --------------------------------------------------------------------------------- 73.09s reboot_ok ------------------------------------------------------------------------------------ 0.86s Gathering Facts ------------------------------------------------------------------------------ 0.86s stat_fileR ----------------------------------------------------------------------------------- 0.30s create_fileR --------------------------------------------------------------------------------- 0.29s
genérer une clée ssh et la deployer
ans@disi-dellat:~/ansible$ cat 07_playbook_ssh_key.yml --- - name: J_Playbook_sshKey hosts: node3 become: yes tasks: - name: create_sshKey openssh_keypair: path: "/tmp/ssh-ans-key" type: rsa size: 2048 state: present force: no #delegate a localhost pour jouer ça sur notre server-node delegate_to: localhost #le faire tourner une seule fois , meme si +sieurs hosts run_once: yes
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 07_playbook_ssh_key.yml BECOME password: PLAY [J_Playbook_sshKey] **************************************************************************** TASK [Gathering Facts] ****************************************************************************** Saturday 20 August 2022 20:45:52 +0200 (0:00:00.017) 0:00:00.017 ******* ok: [node3] TASK [create_sshKey] ******************************************************************************** Saturday 20 August 2022 20:45:53 +0200 (0:00:00.860) 0:00:00.877 ******* changed: [node3 -> localhost] PLAY RECAP ****************************************************************************************** node3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Saturday 20 August 2022 20:45:53 +0200 (0:00:00.208) 0:00:01.085 ******* =============================================================================== Gathering Facts ------------------------------------------------------------------------------ 0.86s create_sshKey -------------------------------------------------------------------------------- 0.21s ans@disi-dellat:~/ansible$ ls -ltr /tmp/ssh* -rw-r--r-- 1 root root 382 août 20 20:45 /tmp/ssh-ans-key.pub -rw------- 1 root root 1799 août 20 20:45 /tmp/ssh-ans-key
apres generation locale de la clé (pas besoin d'elevation de privilege (become)) , on crée un user (become necessaire) , l'ajoute dans sudoers et on lui pousse la clé :
ans@disi-dellat:~/ansible$ cat 07_playbook_ssh_key.yml --- - name: J_Playbook_sshKey hosts: node3 become: yes tasks: - name: create_sshKey openssh_keypair: path: "/tmp/ssh-adma-key" type: rsa size: 2048 state: present force: no #delegate a localhost pour jouer ça sur notre server-node delegate_to: localhost #le faire tourner une seule fois , meme si +sieurs hosts run_once: yes - name: create_user_adma user: name: adma shell: /bin/bash groups: sudo append: yes password: "{{ '1pAA2022.' | password_hash('sha256') }}" become: yes - name: add_adma_sudoers copy: dest: "/etc/sudoers.d/sudoers-adma" content: "adma ALL=(ALL) NOPASSWD: ALL" become: yes - name: deploy_sshKey authorized_key: user: adma key: "{{ lookup('file', '/tmp/ssh-adma-key.pub') }}" state: present become: yes
ans@disi-dellat:~/ansible$ ansible-playbook -i 01_inventory.yml -u ans -K 07_playbook_ssh_key.yml BECOME password: PLAY [J_Playbook_sshKey] **************************************************************************** TASK [Gathering Facts] ****************************************************************************** Sunday 21 August 2022 10:47:05 +0200 (0:00:00.017) 0:00:00.017 ********* ok: [node3] TASK [create_sshKey] ******************************************************************************** Sunday 21 August 2022 10:47:06 +0200 (0:00:01.254) 0:00:01.271 ********* ok: [node3 -> localhost] TASK [create_user_adma] ***************************************************************************** Sunday 21 August 2022 10:47:06 +0200 (0:00:00.185) 0:00:01.457 ********* changed: [node3] TASK [add_adma_sudoers] ***************************************************************************** Sunday 21 August 2022 10:47:07 +0200 (0:00:00.496) 0:00:01.953 ********* ok: [node3] TASK [deploy_sshKey] ******************************************************************************** Sunday 21 August 2022 10:47:07 +0200 (0:00:00.622) 0:00:02.576 ********* changed: [node3] PLAY RECAP ****************************************************************************************** node3 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 Sunday 21 August 2022 10:47:08 +0200 (0:00:00.660) 0:00:03.236 ********* =============================================================================== Gathering Facts ------------------------------------------------------------------------------ 1.25s deploy_sshKey -------------------------------------------------------------------------------- 0.66s add_adma_sudoers ----------------------------------------------------------------------------- 0.62s create_user_adma ----------------------------------------------------------------------------- 0.50s create_sshKey -------------------------------------------------------------------------------- 0.19s