Respostas:
É bem simples mesmo. Você pode compactar seus diferentes itens vars_files em uma única tupla e o Ansible passará automaticamente por cada um deles até encontrar um arquivo existente e carregá-lo. Ex:
vars_files:
- [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
De acordo com os desenvolvedores da Ansible , a maneira correta de resolver isso é usar algo como:
vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]
- include_vars: "{{ item }}"
with_first_found: vars_files_locs
Além disso, eles dizem :
O acima irá carregar corretamente apenas o primeiro arquivo encontrado e é mais flexível do que tentar fazer isso através da
vars_files
palavra-chave language.
include_vars
na tarefa dará uma alta precedência de variáveis em relação à função defaults
ou #vars
Eu encontrei esse problema em uma instalação na qual eu precisava criar vários ambientes de implantação (ao vivo, demo, sandbox) no mesmo servidor físico (não são permitidas máquinas virtuais aqui) e, em seguida, um script para implantar repositórios svn arbitrários
Isso requeria uma árvore de diretórios de arquivos variable.yml (opcionais), que se fundissem uns sobre os outros e não gerasse uma exceção, se houver alguma, em falta
Comece ativando a mesclagem de variáveis no ansible - observe que isso faz a mesclagem superficial de hash (1 nível de profundidade) e não é a mesclagem profunda totalmente recursiva
[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
Essa é a lógica principal de uma árvore de diretórios de arquivos variáveis opcionais.
;; 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"
Configurar variáveis padrão para o projeto e vários usuários e ambientes
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
padrões do projeto
ansible_project:
node_env: development
node_port: 4200
nginx_port: 4400
padrões para project_1
ansible_project:
node_port: 4201
nginx_port: 4401
padrões para ambiente ativo, substitui os padrões do projeto
ansible_project:
node_env: production
substituições finais para project_1 no ambiente ativo
ansible_project:
nginx_port: 80
Configurar playbooks separados para cada 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 }
AVISO: Como todos os ambientes vivem em um único host, todos os playbooks devem ser executados individualmente; caso contrário, o Ansible tentará executar todos os scripts como o primeiro usuário de login ssh e usará apenas as variáveis para o primeiro usuário. Se você precisar executar todos os scripts seqüencialmente, use xargs para executá-los como comandos separados.
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 }}"
Nota: Os testes de caminho (é um arquivo, existe, ...) funcionam apenas com caminhos absolutos ou caminhos relativos ao diretório de trabalho atual ao executar o comando ansible-playbook. Esta é a razão pela qual usamos a pesquisa. a pesquisa aceita caminhos relativos ao diretório do manual e retorna o caminho absoluto quando o arquivo existe.
Ou de uma maneira mais divertida:
- 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 }}"
Ou seja, em vez de escrever uma matriz em uma linha com colchetes, como:
['path/to/file1', 'path/to/file2', ...]
Use a maneira yaml de escrever valores de matriz em várias linhas, como:
- path/to/file1
- path/to/file2
Conforme mencionado, ele procura um arquivo vars chamado {{ ansible_hostname }}.yml
, e se ele não existir, usadefault.yml
Nova resposta com base nas versões mais recentes do Ansible - basicamente, você deve usar with_first_found
, além skip: true
de pular a tarefa se nenhum arquivo for encontrado.
- name: Include vars file if one exists meeting our condition.
include_vars: "{{ item }}"
with_first_found:
- files:
- vars/{{ variable_here }}.yml
skip: true
Isso faz com que você não precise ter um arquivo de fallback vars nessa lista.
Veja relacionados: /programming//a/39544405/100134