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.