Risposte:
È abbastanza semplice davvero. Puoi comprimere i tuoi diversi elementi vars_files in una singola tupla e Ansible passerà automaticamente attraverso ognuno di essi fino a quando non trova un file esistente e lo carica. Ex:
vars_files:
- [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Secondo gli sviluppatori Ansible , il modo corretto di risolverlo è usare qualcosa come:
vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]
- include_vars: "{{ item }}"
with_first_found: vars_files_locs
Inoltre, dicono :
Quanto sopra caricherà correttamente solo il primo file trovato ed è più flessibile del tentativo di farlo tramite la
vars_files
parola chiave language.
include_vars
nel compito darà una precedenza elevata di variabili rispetto al ruolo defaults
ovars
Ho riscontrato questo problema in una configurazione in cui avevo bisogno di creare più ambienti di distribuzione (live, demo, sandbox) sullo stesso server fisico (qui non sono consentite le macchine virtuali) e quindi uno script per distribuire repository svn arbitrari
Ciò ha richiesto un albero di directory di file (facoltativi) variabili.yml, che si unirebbero l'uno sopra l'altro e non genererebbero un'eccezione se mancava
Inizia abilitando l'unione variabile in ansible - nota che questo fa fusione hash superficiale (1 livello di profondità) e fusione profonda non completamente ricorsiva
[defaults]
hash_behaviour=merge ;; merge rather than replace dictionaries http://docs.ansible.com/ansible/intro_configuration.html###hash-behaviour
/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
Questa è la logica principale per un albero di directory di file variabili opzionali.
;; 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"
Configurare le variabili predefinite per il progetto e vari utenti e ambienti
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
valori predefiniti del progetto
ansible_project:
node_env: development
node_port: 4200
nginx_port: 4400
valori predefiniti per project_1
ansible_project:
node_port: 4201
nginx_port: 4401
impostazioni predefinite per l'ambiente live, sostituisce le impostazioni predefinite del progetto
ansible_project:
node_env: production
sostituzioni finali per project_1 nell'ambiente live
ansible_project:
nginx_port: 80
Configura playbook separati per ogni ambiente
- 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 }
ATTENZIONE: Poiché tutti gli ambienti vivono su un singolo host, tutti i playbook devono essere eseguiti singolarmente, altrimenti Ansible tenterà in modo errato di eseguire tutti gli script come primo utente di login ssh e utilizzerà solo le variabili per il primo utente. Se è necessario eseguire tutti gli script in sequenza, utilizzare xargs per eseguirli ciascuno come comandi separati.
find ./playbooks/*.yml | xargs -L1 time ansible-playbook
- 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 }}"
Nota: i test dei percorsi (è file, esiste, ...) funzionano solo con percorsi assoluti o percorsi relativi alla directory di lavoro corrente quando si esegue il comando ansible-playbook. Questo è il motivo per cui abbiamo usato la ricerca. la ricerca accetta i percorsi relativi alla directory del playbook e restituisce il percorso assoluto quando esiste il file.
O in un modo più 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 }}"
Cioè, invece di scrivere un array su una riga con parentesi quadre, come:
['path/to/file1', 'path/to/file2', ...]
Usa il modo yaml di scrivere valori di array su più righe, come:
- path/to/file1
- path/to/file2
Come accennato, questo cerca un file Vars denominato {{ ansible_hostname }}.yml
e, se non esiste, utilizzadefault.yml
Nuova risposta basata sulle ultime versioni di Ansible: in sostanza, è necessario utilizzare with_first_found
, insieme a, skip: true
per saltare l'attività se non viene trovato alcun file.
- name: Include vars file if one exists meeting our condition.
include_vars: "{{ item }}"
with_first_found:
- files:
- vars/{{ variable_here }}.yml
skip: true
Questo lo rende quindi non è necessario disporre di un file di fallback nell'elenco.
Vedi correlati: /programming//a/39544405/100134