Ansible: Могу ли я использовать vars_files, когда некоторые файлы не существуют

17

Это часть:

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

Если файл vars/vars.ymlне существует - здесь ошибка.

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

Как я могу загрузить дополнительные переменные из этого файла, только если он существует? (без ошибок)

Сергей
источник

Ответы:

27

Это довольно просто на самом деле. Вы можете объединить свои различные элементы vars_files в один кортеж, и Ansible будет автоматически просматривать каждый из них, пока не найдет существующий файл и не загрузит его. Пример:

vars_files:
  - [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Garrett
источник
4
По словам разработчиков Ansible , это решение будет загружать все файлы, а не только первый найденный.
tjanez
10

По словам разработчиков Ansible , правильный способ решить эту проблему - использовать что-то вроде:

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

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

Кроме того, они говорят :

Вышеуказанное правильно загрузит только первый найденный файл, и оно более гибкое, чем попытка сделать это с помощью vars_filesключевого слова language.

tjanez
источник
«найден только первый файл» - идея состояла в том, чтобы переопределить некоторые переменные, а не все
Сергей
@ Сергей, перечитывая твой вопрос, я вижу, что ты хотел немного другого. Спасибо за указание на это. Я оставлю ответ как есть, если кто-то найдет его полезным.
tjanez
1
за исключением того, что include_varsв задании будет дан высокий приоритет переменных по сравнению с ролью defaultsилиvars
Alex F
2

Я столкнулся с этой проблемой в установке, где мне нужно было создать несколько сред развертывания (live, demo, sandbox) на одном физическом сервере (здесь не разрешено использование виртуальных машин), а затем скрипт для развертывания произвольных репозиториев SVN.

Для этого требовалось дерево каталогов (необязательных) файлов variable.yml, которые сливались бы друг с другом и не создавали исключение, если таковое отсутствует

Начните с включения слияния переменных в ansible - обратите внимание, что это делает мелкое слияние хешей (1 уровень в глубину) и не полностью рекурсивное глубокое слияние

ansible.cfg

[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

Роли / развернуть / задачи / includes.yml

Это основная логика для дерева каталогов необязательных переменных файлов.

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

Настройте переменные по умолчанию для проекта и различных пользователей и сред

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

Роли / развернуть / вары / main.yml

проект по умолчанию

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

Роли / развернуть / вары / project_1.yml

значения по умолчанию для project_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

Роли / развернуть / вары / живой / main.yml

значения по умолчанию для живой среды, переопределяет значения по умолчанию проекта

ansible_project:
  node_env: production

Роли / развернуть / вары / живой / project_1.yml

окончательные переопределения для project_1 в живой среде

ansible_project:
  nginx_port: 80

playbooks / demo.yml

Настроить отдельные книги для каждой среды

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

ПРЕДУПРЕЖДЕНИЕ. Поскольку все среды находятся на одном хосте, все playbook-ы должны запускаться по отдельности, в противном случае Ansible будет безуспешно пытаться запустить все сценарии как первый пользователь ssh и будет использовать переменные только для первого пользователя. Если вам нужно запустить все сценарии последовательно, используйте xargs для запуска каждого из них в виде отдельных команд.

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

Примечание. Тесты пути (это файл, существует, ...) работают только с абсолютными путями или путями относительно текущего рабочего каталога при выполнении команды ansible-playbook. Это причина, по которой мы использовали поиск. поиск принимает пути относительно каталога playbook и возвращает абсолютный путь, когда файл существует.

Ejez
источник
0

Или в более ярком смысле:

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

То есть вместо записи массива в одну строку в квадратных скобках, например:

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

Используйте способ yaml для записи значений массива в несколько строк, например:

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

Как уже упоминалось, это ищет файл vars с именем {{ ansible_hostname }}.yml, и если он не существует, используетdefault.yml

Донн Ли
источник
Этот ответ использует тот же код, что и этот, за исключением того, что он использует другие данные. А именно {{ ansible_hostname }}.ymlимя файла вместо ../path/to/file1. В чем смысл? Можно добавить неограниченное количество имен входных файлов.
techraf
@techraf: Хорошо, я добавил некоторые пояснения / уточнения, почему был представлен новый ответ. Это связано с тем, что комментарии о сбое сервера не поддерживают фрагменты многострочного кода, и я просто подчеркивал, что массивы yaml часто (предпочтительно?) Пишутся в несколько строк. Также было бы хорошо, если бы предыдущий ответ был отредактирован и отображался формат многострочного массива, как я вижу это чаще. Тогда мой ответ может быть удален.
Донн Ли
Обе записи указаны в Ansible docs в главе Основы YAML . Тот факт, что вы видите одно чаще другого, еще не делает это новым ответом.
techraf
0

Соединение различных частей вместе ... include_vars с предложением when, которое имеет значение true, когда файл существует. т.е.

vars:
  file_to_include: /path/to/file
tasks:
  - include_vars: "{{ file_to_include }}"
    when: file_to_include is exists
pedz
источник
0

Новый ответ, основанный на последних версиях Ansible - в основном, вы должны использовать with_first_foundнаряду с skip: trueпропуском задачи, если файл не найден.

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

Это позволяет вам не иметь запасного файла vars в этом списке.

Смотрите связанные: /programming//a/39544405/100134

geerlingguy
источник