Відповіді:
Насправді це дуже просто. Ви можете розрізати різні елементи vars_files в один кордон, і Ansible автоматично проходитиме кожен з них, поки не знайде файл, який існує, і не завантажить його. Наприклад:
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
мовного ключового слова.
include_vars
в завданні буде надано високий пріоритет змінних порівняно з роллю defaults
абоvars
Я зіткнувся з цією проблемою в налаштуваннях, де мені потрібно було створити кілька середовищ розгортання (в прямому ефірі, демо, пісочниці) на одному фізичному сервері (тут не дозволено віртуальних машин), а потім сценарій для розгортання довільних svn repos
Для цього потрібне дерево каталогів (необов'язково) файлів varia.yml, яке б злилося на вершині один одного і не викидало виняток, якщо таке взагалі відсутнє
Почніть з включення змінного злиття в ansible - зауважте, що це неглибоке злиття хешу (глибина 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
за замовчуванням для проекту_1
ansible_project:
node_port: 4201
nginx_port: 4401
за замовчуванням для живого середовища, замінює параметри за замовчуванням для проекту
ansible_project:
node_env: production
остаточні зміни для проекту_1 у прямому середовищі
ansible_project:
nginx_port: 80
Налаштуйте окремі ігрові книги для кожного середовища
- 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 }
ПОПЕРЕДЖЕННЯ: Оскільки всі середовища живуть на одному хості, всі ігрові книги повинні запускатися окремо, інакше 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. З цієї причини ми використовували пошук. пошук приймає шляхи відносно каталогу ігрової книги та повертає абсолютний шлях, коли файл існує.
Або більш ямл-способом:
- 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 - в основному, ви повинні використовувати 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