Table des matières
0 billet(s) pour février 2026
Notes Ansible boucle loop
Exemple équivalent à une boucle for imbriqué dans une boucle for, grâce au filtre product
#! /usr/bin/ansible-playbook - name: play test loop hosts: localhost vars: objects: - pomme - banane emails: - 'root@localhost' - 'plop@acme.fr' tasks: - name: Exemple boucle debug: msg: "{{ object }} - {{ email }}" vars: object: "{{ item.0 }}" email: "{{ item.1 }}" loop: "{{ objects | product(emails) | list }}"
ok: [localhost] => (item=['pomme', 'root@localhost']) => { "msg": "pomme - root@localhost" } ok: [localhost] => (item=['pomme', 'plop@acme.fr']) => { "msg": "pomme - plop@acme.fr" } ok: [localhost] => (item=['banane', 'root@localhost']) => { "msg": "banane - root@localhost" } ok: [localhost] => (item=['banane', 'plop@acme.fr']) => { "msg": "banane - plop@acme.fr" }
Ansible loop break
#!/usr/bin/ansible-playbook --- - name: test hosts: localhost tasks: - name: break 1 command: "echo {{ item }}" register: res with_sequence: 0-100 when: - item |int > 3 - not (res.changed|d(false)) - name: break 2 set_fact: id: "{{ item }}" register: res2 with_sequence: 0-100 # Because set_fact not make "change" changed_when: item |int > 3 when: - not (res2.changed|d(false)) # Ca fonctionne mais # * hélas ce n'est pas un vrai Break car il boucle sur toutes les valeurs # * plus problématique encore, ce n'est pas idempotent, car il fait un "Change" à chaque appel # Nous préférerons utiliser les listes - name: break 3-A set_fact: ids: "{{ ids | d([]) + [ item | int ] }}" with_sequence: 0-100 when: item |int > 3 - name: break 3-B debug: msg: "{{ ids | min }}"
Notes Ansible ansible-navigator
Config
ansible.cfg
# Since Ansible 2.12 (core): # To generate an example config file (a "disabled" one with all default settings, commented out): # $ ansible-config init --disabled > ansible.cfg # # Also you can now have a more complete file by including existing plugins: # ansible-config init --disabled -t all > ansible.cfg # # Voir la configuration : # ansible-config dump --only-changed -t all # For previous versions of Ansible you can check for examples in the 'stable' branches of each version # Note that this file was always incomplete and lagging changes to configuration settings # for example, for 2.9: https://github.com/ansible/ansible/blob/stable-2.9/examples/ansible.cfg [galaxy] server_list = rh-certified_repo, published_repo, community_repo, galaxy, dev-community [galaxy_server.rh-certified_repo] token=000000000000000 url=https://aap.acme.local/api/galaxy/content/rh-certified/ [galaxy_server.published_repo] token=000000000000000 url=https://aap.acme.local/api/galaxy/content/published/ [galaxy_server.community_repo] token=000000000000000 url=https://aap.acme.local/api/galaxy/content/community/ [galaxy_server.galaxy] url=https://galaxy.ansible.com/ [galaxy_server.dev-community] url=https://aah.acme.local/api/galaxy/content/community/ token=000000000000000
~/.ansible-navigator.yml
# # cspell:ignore cmdline, workdir --- ansible-navigator: ansible: config: path: ./ansible.cfg execution-environment: container-engine: podman enabled: true image: image-standard:0.9.1 logging: level: warning
Exemple
Lancer un playbook
ansible-navigator --ee false –m stdout playbook.yml –l server01
Afficher les infos sur une image
ansible-navigator --eei ADRESSE_HUB/EE:X.Y.Z images -d
Lancer un playbook dans un Execution Environment donné
podman images podman login --tls-verify=false aap.acme.local -u jean@acme.local
ansible-navigator -m stdout run play.yml -i localhost, -c local -vv --eei aap.acme.local/image-standard:0.9.1
inv.txt
localhost ansible_connection=local ansible_python_interpreter=/usr/bin/python
ansible-navigator -m stdout run -i inv.txt --ee true --eei acme-automationhub-prod.admin.acme.local/acme-opn_lnx-recommended:0.9.4 /home/admin/play-mssql.yml
Lister les images
ansible-navigator -m stdout images | egrep '\sname:' |egrep -v '/|overlay' |awk '{print $2}'
Avoir les informations sur une image
ansible-navigator -m stdout --eei localhost/plop images -d python_version ansible-navigator -m stdout --eei localhost/plop images -d ansible_version
Notes Ansible - Validate - file name extension
Le “validate” d'Ansible ne fonctionne pas si la commande de validation est tributaire de l’extension (la fin du nom de fichier après le point communément de 3 ou 4 caractères).
En effet le fichier poussé par Ansible n'est pas tout de suite nommé de son nom définitif.
La solution est de créer un script “wraper” pour envelopper la commande de validation. Il se chargera de le nommer comme il se doit avant.
Voici un exemple avec une validation d'un fichier Unit de SystemD.
files/wrapper_systemd-analyze_verify.sh
#! /bin/bash # Wrapper for Ansible M(template) A(validate) # Because 'systemd-analyze verify' work only when file is named with correct extention like .service .socket or .timer # Used by R(CDO_SET_SERVICE_FILE) FICNAME="$1" get_type() { if [[ "$(cat $FICNAME)" =~ '[Service]' ]] then echo '.service' elif [[ "$(cat $FICNAME)" =~ '[Socket]' ]] then echo '.socket' elif [[ "$(cat $FICNAME)" =~ '[Timer]' ]] then echo '.timer' else echo "ERROR getting type" exit 3 fi } NEW_FICNAME="$(basename $FICNAME)$(get_type)" ln -fs "$FICNAME" "$NEW_FICNAME" systemd-analyze verify "$NEW_FICNAME" RET=$? unlink "$NEW_FICNAME" exit $RET
- name: hack - wrapper to systemd-analyze_verify for validate become: true become_user: "{{ becomeuser }}" when: unit_file_comp.changed block: - name: make dir into .ansible/tmp-files/ file: path="{{ homedir }}/.ansible/tmp-files/" state=directory recurse=true - name: copy script for validate wrapper_systemd-analyze_verify.sh copy: src: wrapper_systemd-analyze_verify.sh dest: "{{ homedir }}/.ansible/tmp-files/" mode: 0755 - name: template systemd unit file template: src: systemd-unit.j2 dest: "{{ systemd_file_path }}" validate: "{{ homedir }}/.ansible/tmp-files/wrapper_systemd-analyze_verify.sh %s"
Notes Ansible - test ports de connexion SSH
Voir aussi :
- block / rescue
Context :
Le port par défaut pour SSH est le 22.
Nous changeons habituellement ce port en 2222.
Nous écrivons un playbook capable d’adresser les machines avec SSH configuré avec le port 2222 ainsi que celles configurées avec le port 22.
wrapper_ssh_ports.yml
--- - name: wrapper_both_ssh_ports hosts: all gather_facts: false vars: port_test_1: 2222 port_test_2: 22 tasks: - name: set_fact port_test_1 set_fact: ansible_port: "{{ port_test_1 }}" - name: ping 1 ignore_unreachable: true ping: register: ping_1 - name: set_fact port_test_2 when: not ( ping_1.ping is defined and ping_1.ping == 'pong' ) set_fact: ansible_port: "{{ port_test_2 }}" - name: ping 2 when: not ( ping_1.ping is defined and ping_1.ping == 'pong' ) ignore_unreachable: true ping: register: ping_2 - name: fail when all ports NOK assert: that: - ( ping_1.ping is defined and ping_1.ping == 'pong' ) or ( ping_2.ping is defined and ping_2.ping == 'pong' ) msg: "Fail unreachable target" - import_playbook: play2.yml
play2.yml
- name: playbook to launch always - SSH port 2222 and 22 hosts: all gather_facts: false tasks: - name: commande uptime command: uptime changed_when: false register: uptime - name: echo uptime debug: var: uptime.stdout
Notes Ansible - mount - prevent nested loops
Nous voulons interdire les montages imbriqués (montage dans un montage)
Ou pour le dire autrement : Nous voulons interdire à un utilisateur de créer un point de montage dans un point de montage existant (autre que /).
playbook.yml
- name: is a nested mount ? become: true shell: | # will_be_mounted_on # Returns the mount point where the future file given in argument will be located set -euo pipefail TMP_PATH="{{ PLOP_ACCOUNT_HOME | quote }}" while [[ ! -e "$TMP_PATH" ]] do TMP_PATH="$(dirname $TMP_PATH)" done df -l --output=target "$TMP_PATH" | tail -1 check_mode: false changed_when: false register: mounted_on when: PLOP_ACCOUNT_HOME is defined and PLOP_ACCOUNT_HOME != '' - name: assert fail on nested mount assert: that: - mounted_on.stdout_lines[-1] == '/' or mounted_on.stdout_lines[-1] == PLOP_ACCOUNT_HOME
