Это часть:
vars_files:
- vars/vars.default.yml
- vars/vars.yml
Если файл vars/vars.yml
не существует - вот ошибка.
ERROR: file could not read: /.../vars/vars.yml
Как я могу загрузить дополнительные переменные из этого файла, только если он существует? (без ошибок)
На самом деле это довольно просто. Вы можете объединить различные элементы vars_files в один кортеж, и Ansible будет автоматически просматривать каждый из них, пока не найдет существующий файл и не загрузит его. E.x .:
vars_files:
- [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
В соответствии с Ansible разработчики, то правильный способ решить эту проблему - использовать что-то вроде:
vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]
- include_vars: "{{ item }}"
with_first_found: vars_files_locs
Более того, они говорят:
Вышеупомянутое будет правильно загружать только первый найденный файл и является более гибким, чем попытка сделать это через
vars_files
ключевое слово языка.
Я столкнулся с этой проблемой в настройке, где мне нужно было создать несколько сред развертывания (live, demo, sandbox) на одном физическом сервере (здесь не разрешены виртуальные машины), а затем сценарий для развертывания произвольных репозиториев svn
Для этого требовалось дерево каталогов (необязательных) файлов variable.yml, которые будут сливаться друг над другом и не генерировать исключение, если оно отсутствует.
Начните с включения слияния переменных в анзибле - обратите внимание, что при этом выполняется неглубокое слияние хэшей (глубина 1 уровня), а не полностью рекурсивное глубокое слияние
[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
Это основная логика для дерева каталогов необязательных файлов переменных.
;; 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"
Настроить переменные по умолчанию для проекта и различных пользователей и сред
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
параметры проекта по умолчанию
ansible_project:
node_env: development
node_port: 4200
nginx_port: 4400
значения по умолчанию для project_1
ansible_project:
node_port: 4201
nginx_port: 4401
значения по умолчанию для живой среды, отменяет значения по умолчанию для проекта
ansible_project:
node_env: production
окончательные переопределения для project_1 в реальной среде
ansible_project:
nginx_port: 80
Настройте отдельные playbooks для каждой среды
- 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 }
ПРЕДУПРЕЖДЕНИЕ: поскольку все среды находятся на одном хосте, все playbooks должны запускаться индивидуально, иначе Ansible будет некорректно пытаться запустить все сценарии как первый пользователь ssh и использовать переменные только для первого пользователя. Если вам нужно запускать все сценарии последовательно, используйте xargs для запуска каждого из них как отдельных команд.
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 }}"
Примечание. Тесты пути (это файл, существует, ...) работают только с абсолютными путями или путями относительно текущего рабочего каталога при выполнении команды ansible-playbook. Это причина, по которой мы использовали поиск. поиск принимает пути относительно каталога playbook и возвращает абсолютный путь, если файл существует.
Или более ямльным способом:
- 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
Соединение различных частей вместе ... include_vars с предложением when, которое истинно, когда файл существует. т.е.
vars:
file_to_include: /path/to/file
tasks:
- include_vars: "{{ file_to_include }}"
when: file_to_include is exists
Новый ответ, основанный на последних версиях 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 в этом списке.
См. Связанные: https://stackoverflow.com/a/39544405/100134