Outils pour utilisateurs

Outils du site


blog

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 }}"
2025/03/24 15:06

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
2025/03/24 15:06

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"
2025/03/24 15:06

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
2025/03/24 15:06

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
2025/03/24 15:06
blog.txt · Dernière modification : de 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki