Odpowiedź: Czy mogę używać plików vars, gdy niektóre pliki nie istnieją

17

To jest część:

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

Jeśli plik vars/vars.ymlnie istnieje - występuje błąd.

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

Jak mogę załadować dodatkowe zmienne z tego pliku, tylko jeśli istnieje? (bez błędów)

Siergiej
źródło

Odpowiedzi:

27

To naprawdę bardzo proste. Możesz zgnieść różne elementy vars_files w jedną krotkę, a Ansible automatycznie przejrzy każdy z nich, dopóki nie znajdzie pliku, który istnieje i załaduje go. Dawny:

vars_files:
  - [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Garrett
źródło
4
Według twórców Ansible rozwiązanie to załaduje wszystkie pliki, nie tylko pierwszy znaleziony.
tjanez
10

Według ansibl twórców The właściwy sposób na rozwiązanie tego problemu jest użycie coś takiego:

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

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

Ponadto mówią :

Powyższe poprawnie załaduje tylko pierwszy znaleziony plik i jest bardziej elastyczne niż próba zrobienia tego za pomocą vars_filessłowa kluczowego language.

tjanez
źródło
„znaleziono tylko pierwszy plik” - pomysł polegał na ponownym zdefiniowaniu niektórych zmiennych, a nie wszystkich
Sergey
@Sergey, czytając ponownie twoje pytanie, widzę, że to, czego chciałeś, jest nieco inne. Dzięki za zwrócenie na to uwagi. Pozostawię odpowiedź tak, jak gdyby ktoś inny uznał ją za przydatną.
tjanez
1
z wyjątkiem tego, że include_varsw zadaniu da wysoki priorytet zmiennym w porównaniu do roli defaultslubvars
Alex F
2

Napotkałem ten problem w konfiguracji, w której musiałem utworzyć wiele środowisk wdrażania (na żywo, demo, piaskownicy) na tym samym serwerze fizycznym (tutaj niedozwolone maszyny wirtualne), a następnie skrypt do wdrożenia dowolnych repozytoriów svn

Wymagało to drzewa katalogów (opcjonalnych) plików zmiennych.yml, które połączyłyby się jeden na drugim i nie zgłaszałyby wyjątku, jeśli go brakuje

Zacznij od umożliwienia łączenia zmiennych w ansible - zwróć uwagę, że powoduje to płytkie scalanie skrótów (głębokość 1 poziomu) i niepełne rekurencyjne scalanie głębokie

ansible.cfg

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

Układ katalogu 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

role / deploy / tasks / obejmuje.yml

Jest to główna logika drzewa katalogów opcjonalnych plików zmiennych.

;; 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

Skonfiguruj zmienne domyślne dla projektu oraz różnych użytkowników i środowisk

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

roles / deploy / vars / main.yml

ustawienia domyślne projektu

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

role / deploy / vars / project_1.yml

domyślne dla projektu_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

roles / deploy / vars / live / main.yml

wartości domyślne dla środowiska na żywo, przesłania wartości domyślne projektu

ansible_project:
  node_env: production

role / deploy / vars / live / project_1.yml

końcowe przesłonięcia projektu_1 w środowisku na żywo

ansible_project:
  nginx_port: 80

podręczniki / demo.yml

Skonfiguruj osobne podręczniki dla każdego środowiska

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

OSTRZEŻENIE: Ponieważ wszystkie środowiska działają na jednym hoście, wszystkie podręczniki muszą być uruchamiane indywidualnie, w przeciwnym razie Ansible zepsuje próbę uruchomienia wszystkich skryptów jako pierwszy użytkownik logowania ssh i użyje zmiennych tylko dla pierwszego użytkownika. Jeśli musisz uruchomić wszystkie skrypty sekwencyjnie, użyj xargs, aby uruchomić je osobno.

find ./playbooks/*.yml | xargs -L1 time ansible-playbook
James McGuigan
źródło
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 }}"

Uwaga: Testy ścieżek (plik, istnieje, ...) działają tylko z bezwzględnymi ścieżkami lub ścieżkami względem bieżącego katalogu roboczego podczas uruchamiania polecenia ansible-playbook. To jest powód, dla którego użyliśmy wyszukiwania. wyszukiwanie akceptuje ścieżki względem katalogu podręcznika i zwraca bezwzględną ścieżkę, gdy plik istnieje.

Ejez
źródło
0

Lub w bardziej yamlowy sposób:

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

Oznacza to, że zamiast pisać tablicę w jednym wierszu za pomocą nawiasów kwadratowych, na przykład:

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

Użyj yamlowego sposobu zapisywania wartości tablic w wielu wierszach, takich jak:

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

Jak wspomniano, szuka pliku vars o nazwie {{ ansible_hostname }}.yml, a jeśli nie istnieje, używadefault.yml

Donn Lee
źródło
Ta odpowiedź używa tego samego kodu, co ten, z wyjątkiem tego, że używa innych danych. Mianowicie {{ ansible_hostname }}.ymlnazwa pliku zamiast ../path/to/file1. Jaki jest sens? Można dodać nieograniczoną liczbę nazw plików wejściowych.
techraf
@techraf: Ok, dodałem wyjaśnienie / wyjaśnienie, dlaczego przesłano nową odpowiedź. To dlatego, że komentarze o błędach serwera nie obsługują fragmentów kodu wielowierszowego, a ja właśnie zauważyłem, że tablice yaml są często (najlepiej?) Zapisywane w wielu wierszach. Byłbym również w porządku, gdyby edytowano wcześniejszą odpowiedź i pokazano format tablicy z wieloma wierszami, ponieważ widzę to częściej. Następnie moją odpowiedź można usunąć.
Donn Lee
Obie notacje są określone w Ansible docs w rozdziale YAML Basics . Fakt, że widzisz jedną częściej niż drugą, nie czyni z niej nowej odpowiedzi.
techraf
0

Składanie różnych elementów razem ... include_vars z klauzulą ​​when, która jest prawdziwa, gdy plik istnieje. to znaczy

vars:
  file_to_include: /path/to/file
tasks:
  - include_vars: "{{ file_to_include }}"
    when: file_to_include is exists
pedz
źródło
0

Nowa odpowiedź oparta na najnowszych wersjach Ansible - w zasadzie powinieneś użyć with_first_foundwraz z, skip: trueaby pominąć zadanie, jeśli nie znaleziono pliku.

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

To sprawia, że ​​nie musisz mieć pliku rezerwowego na tej liście.

Zobacz powiązane: /programming//a/39544405/100134

geerlingguy
źródło