Ansible: posso usare vars_files quando alcuni file non esistono


17

Questa è la parte:

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

Se un file vars/vars.ymlnon esiste, ecco un errore.

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

Come posso caricare ulteriori variabili da questo file solo se esiste? (senza errori)

Risposte:


27

È 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" ]

4
Secondo gli sviluppatori Ansible , questa soluzione caricherà tutti i file, non solo il primo trovato.
tjanez,

10

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_filesparola chiave language.


"trovato solo il primo file" - l'idea era di ridefinire alcune variabili, non tutte
Sergey

@Sergey, rileggendo la tua domanda, vedo che quello che volevi è un po 'diverso. Grazie per averlo segnalato. Lascio la risposta com'è se qualcun altro la trova utile.
tjanez,

1
tranne che include_varsnel compito darà una precedenza elevata di variabili rispetto al ruolo defaultsovars
Alex F

2

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

ansible.cfg

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

Layout della directory Ansible

/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

ruoli / deploy / attività / includes.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"

group_vars / all.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

ruoli / deploy / vars / main.yml

valori predefiniti del progetto

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

ruoli / deploy / vars / project_1.yml

valori predefiniti per project_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

ruoli / deploy / vars / live / main.yml

impostazioni predefinite per l'ambiente live, sostituisce le impostazioni predefinite del progetto

ansible_project:
  node_env: production

ruoli / deploy / vars / live / project_1.yml

sostituzioni finali per project_1 nell'ambiente live

ansible_project:
  nginx_port: 80

Playbook / demo.yml

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

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 }}"

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.


0

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 }}.ymle, se non esiste, utilizzadefault.yml


Questa risposta utilizza lo stesso codice di questa tranne per il fatto che utilizza dati diversi. Vale a dire {{ ansible_hostname }}.ymlil nome del file anziché ../path/to/file1. Qual e il punto? Si può aggiungere un numero illimitato di nomi di file di input.
techraf,

@techraf: Ok, ho aggiunto alcuni chiarimenti / amplificazioni sul perché è stata inviata una nuova risposta. È perché i commenti serverfault non supportano gli snippet di codice multilinea e stavo solo sottolineando che le matrici yaml sono frequentemente (preferibilmente?) Scritte su più righe. Andrei anche bene se la risposta precedente fosse modificata e fosse mostrato il formato dell'array multilinea, come vedo più spesso. Quindi la mia risposta può essere cancellata.
Donn Lee,

Entrambe le notazioni sono specificate in Documenti Ansible in un capitolo Nozioni di base su YAML . Il fatto che tu veda uno più spesso dell'altro non lo rende ancora una nuova risposta.
techraf il

0

Mettere insieme vari pezzi ... include_vars con una clausola when che è vera quando il file esiste. vale a dire

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

0

Nuova risposta basata sulle ultime versioni di Ansible: in sostanza, è necessario utilizzare with_first_found, insieme a, skip: trueper 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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.