Ansible: puis-je utiliser vars_files lorsque certains fichiers n'existent pas

17

Voilà la partie:

vars_files:
  - vars/vars.default.yml
  - vars/vars.yml

Si un fichier vars/vars.ymln'existe pas - voici une erreur.

ERROR: file could not read: /.../vars/vars.yml

Comment puis-je charger des variables supplémentaires à partir de ce fichier uniquement s'il existe? (sans erreur)

Sergey
la source

Réponses:

27

C'est assez simple vraiment. Vous pouvez compresser vos différents éléments vars_files en un seul tuple et Ansible les parcourra automatiquement jusqu'à ce qu'il trouve un fichier qui existe et le charge. Ex:

vars_files:
  - [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Garrett
la source
4
Selon les développeurs d'Ansible , cette solution chargera tous les fichiers, pas seulement le premier trouvé.
tjanez
10

Selon les développeurs d'Ansible , la bonne façon de résoudre ce problème est d'utiliser quelque chose comme:

vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]

- include_vars: "{{ item }}"
  with_first_found: vars_files_locs

De plus, ils disent :

Ce qui précède ne chargera correctement que le premier fichier trouvé et est plus flexible que d'essayer de le faire via le vars_filesmot-clé language.

tjanez
la source
"seul le premier fichier trouvé" - l'idée était de redéfinir certaines variables, pas toutes
Sergey
@Sergey, relisant ta question, je vois que ce que tu voulais est un peu différent. Merci de l'avoir signalé. Je laisse la réponse telle quelle si quelqu'un d'autre la trouve utile.
tjanez
1
sauf que include_varsdans la tâche donnera une priorité élevée des variables par rapport au rôle defaultsouvars
Alex F
2

J'ai rencontré ce problème dans une configuration où j'avais besoin de créer plusieurs environnements de déploiement (en direct, démo, bac à sable) sur le même serveur physique (pas de machines virtuelles autorisées ici), puis un script pour déployer des dépôts svn arbitraires

Cela nécessitait une arborescence de répertoires de fichiers variable.yml (facultatifs), qui fusionneraient les uns sur les autres et ne lèveraient pas d'exception le cas échéant

Commencez par activer la fusion de variables dans ansible - notez que cela fait une fusion de hachage peu profonde (1 niveau de profondeur) et une fusion profonde non récursive

ansible.cfg

[defaults]
hash_behaviour=merge ;; merge rather than replace dictionaries http://docs.ansible.com/ansible/intro_configuration.html###hash-behaviour

Disposition de répertoire possible

/group_vars
└── all.yml

/playbooks
├── boostrap.yml
├── demo.yml
├── live.yml
└── sandbox.yml

/roles/deploy/
├── files
├── tasks
│   ├── includes.yml
│   ├── main.yml
└── vars
    ├── main.yml
    ├── project_1.yml
    ├── project_2.yml
    ├── demo
    │   ├── project_1.yml
    │   ├── project_2.yml   
    │   └── main.yml
    ├── live
    │   ├── project_1.yml
    │   ├── project_2.yml   
    │   └── main.yml
    └── sandbox
        ├── project_1.yml
        ├── project_2.yml   
        └── main.yml

rôles / déployer / tâches / inclut.yml

Il s'agit de la logique principale d'une arborescence de répertoires de fichiers variables facultatifs.

;; imports in this order:
;; - /roles/deploy/vars/main.yml
;; - /roles/deploy/vars/{{ project_name }}.yml
;; - /roles/deploy/vars/{{ project_name }}/main.yml
;; - /roles/deploy/vars/{{ project_name }}/{{ project_env }}.yml
- include_vars:
    dir: 'vars'
    files_matching: "{{ item }}"
    depth: 1
  with_items:
    - "main.yml"
    - "{{ project_name }}.yml"

- include_vars:
    dir: 'vars/{{ env_name }}'
    files_matching: "{{ item }}"
    depth: 1
  with_items:
    - "main.yml"
    - "{{ project_name }}.yml"

group_vars / all.yml

Configurer les variables par défaut pour le projet et divers utilisateurs et environnements

project_users:
    bootstrap:
        env:   bootstrap
        user:  ansible
        group: ansible
        mode:  755
        root:  /cs/ansible/
        home:  /cs/ansible/home/ansible/
        directories:
            - /cs/ansible/
            - /cs/ansible/home/

    live:
        env:   live
        user:  ansible-live
        group: ansible
        mode:  755
        root:  /cs/ansible/live/
        home:  /cs/ansible/home/ansible-live/

    demo:
        env:   demo
        user:  ansible-demo
        group: ansible
        mode:  755
        root:  /cs/ansible/demo/
        home:  /cs/ansible/home/ansible-demo/

    sandbox:
        env:   sandbox
        user:  ansible-sandbox
        group: ansible
        mode:  755
        root:  /cs/ansible/sandbox/
        home:  /cs/ansible/home/ansible-sandbox/    

project_env:  bootstrap
project_user: "{{ ansible_users[project_env] }}" ;; this will be retroactively updated if project_env is redefined later

rôles / deploy / vars / main.yml

valeurs par défaut du projet

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

rôles / deploy / vars / project_1.yml

valeurs par défaut pour project_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

rôles / deploy / vars / live / main.yml

par défaut pour l'environnement en direct, remplace les valeurs par défaut du projet

ansible_project:
  node_env: production

rôles / deploy / vars / live / project_1.yml

substitutions finales pour project_1 dans l'environnement en direct

ansible_project:
  nginx_port: 80

playbooks / demo.yml

Configurer des playbooks séparés pour chaque environnement

- hosts: shared_server
  remote_user: ansible-demo
  vars:
    project_env: demo
  pre_tasks:
    - debug: "msg='{{ facter_gid }}@{{ facter_fqdn }} ({{ server_pseudonym }})'"
    - debug: var=project_ssh_user
  roles:
    - { role: deploy, project_name: project_1 }

AVERTISSEMENT: étant donné que tous les environnements vivent sur un seul hôte, tous les playbooks doivent être exécutés individuellement, sinon Ansible tentera de manière irrégulière d'exécuter tous les scripts en tant que premier utilisateur de connexion ssh et n'utilisera que les variables pour le premier utilisateur. Si vous devez exécuter tous les scripts séquentiellement, utilisez xargs pour les exécuter chacun en tant que commandes distinctes.

find ./playbooks/*.yml | xargs -L1 time ansible-playbook
James McGuigan
la source
1
- hosts: all
  vars_files: vars/vars.default.yml
  vars:
    optional_vars_file: "{{ lookup('first_found', 'vars/vars.yml', errors='ignore') }}"
  tasks:
  - when: optional_vars_file is file
    include_vars: "{{ optional_vars_file }}"

Remarque: Les tests de chemin (est un fichier, existe, ...) ne fonctionnent qu'avec des chemins absolus ou des chemins relatifs au répertoire de travail actuel lors de l'exécution de la commande ansible-playbook. C'est la raison pour laquelle nous avons utilisé la recherche. la recherche accepte les chemins relatifs au répertoire playbook et renvoie le chemin absolu lorsque le fichier existe.

Ejez
la source
0

Ou d'une manière plus yaml:

- hosts: webservers
  vars:
    paths_to_vars_files:
      - vars/{{ ansible_hostname }}.yml
      - vars/default.yml
  tasks:
    - include_vars: "{{ item }}"
      with_first_found: "{{ paths_to_vars_files }}"

Autrement dit, au lieu d'écrire un tableau sur une ligne avec des crochets, comme:

['path/to/file1', 'path/to/file2', ...]

Utilisez la méthode yaml pour écrire des valeurs de tableau sur plusieurs lignes, comme:

- path/to/file1
- path/to/file2

Comme mentionné, cela recherche un fichier vars nommé {{ ansible_hostname }}.yml, et s'il n'existe pas, il utilisedefault.yml

Donn Lee
la source
Cette réponse utilise le même code que celui-ci sauf qu'il utilise des données différentes. À savoir {{ ansible_hostname }}.ymlle nom de fichier au lieu de ../path/to/file1. À quoi ça sert? On peut ajouter un nombre illimité de noms de fichiers d'entrée.
techraf
@techraf: Ok, j'ai ajouté quelques clarifications / amplifications sur les raisons pour lesquelles une nouvelle réponse a été soumise. C'est parce que les commentaires par défaut du serveur ne prennent pas en charge les extraits de code multi-lignes, et je faisais juste remarquer que les tableaux yaml sont fréquemment (de préférence?) Écrits sur plusieurs lignes. Je serais également d'accord si la réponse précédente était modifiée et le format de tableau multi-lignes affiché, comme je le vois plus souvent. Ensuite, ma réponse peut être supprimée.
Donn Lee
Les deux notations sont spécifiées dans les documents Ansible dans un chapitre Bases de YAML . Le fait que vous en voyiez un plus souvent que l'autre n'en fait pas encore une nouvelle réponse.
techraf
0

Assemblage de divers morceaux ensemble ... include_vars avec une clause when qui est vraie lorsque le fichier existe. c'est à dire

vars:
  file_to_include: /path/to/file
tasks:
  - include_vars: "{{ file_to_include }}"
    when: file_to_include is exists
pedz
la source
0

Nouvelle réponse basée sur les dernières versions d'Ansible - en gros, vous devez utiliser with_first_found, ainsi que skip: truepour ignorer la tâche si aucun fichier n'est trouvé.

- name: Include vars file if one exists meeting our condition.
  include_vars: "{{ item }}"
  with_first_found:
    - files:
        - vars/{{ variable_here }}.yml
      skip: true

Cela vous évite d'avoir à avoir un fichier vars de secours dans cette liste.

Voir à ce sujet: /programming//a/39544405/100134

geerlingguy
la source