Respuestas:
Es bastante simple en realidad. Puede aplastar sus diferentes elementos vars_files en una sola tupla y Ansible revisará automáticamente cada uno hasta que encuentre un archivo que exista y lo cargue. Ex:
vars_files:
- [ "vars/foo.yml", "vars/bar.yml", "vars/default.yml" ]
Según los desarrolladores de Ansible , la forma correcta de resolver esto es usar algo como:
vars_files_locs: ['../path/to/file1', '../path/to/file2', ...]
- include_vars: "{{ item }}"
with_first_found: vars_files_locs
Además, dicen :
Lo anterior cargará correctamente solo el primer archivo encontrado, y es más flexible que intentar hacerlo a través de la
vars_files
palabra clave del idioma.
include_vars
en la tarea dará una alta precedencia de variables en comparación con el rol defaults
ovars
Encontré este problema en una configuración en la que necesitaba crear múltiples entornos de implementación (en vivo, demo, sandbox) en el mismo servidor físico (no se permiten máquinas virtuales aquí), y luego un script para implementar repositorios svn arbitrarios
Esto requería un árbol de directorios de archivos variables.yml (opcional), que se fusionarían uno encima del otro y no arrojarían una excepción si faltaba alguna.
Comience habilitando la fusión de variables en ansible: tenga en cuenta que esto hace una fusión hash superficial (1 nivel de profundidad) y no una fusión 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
Esta es la lógica principal para un árbol de directorios de archivos variables opcionales.
;; 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 variables predeterminadas para el proyecto y varios usuarios y entornos.
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
valores predeterminados del proyecto
ansible_project:
node_env: development
node_port: 4200
nginx_port: 4400
valores predeterminados para proyecto_1
ansible_project:
node_port: 4201
nginx_port: 4401
valores predeterminados para el entorno en vivo, anula los valores predeterminados del proyecto
ansible_project:
node_env: production
anulaciones finales para project_1 en el entorno en vivo
ansible_project:
nginx_port: 80
Configure libros de jugadas separados para cada entorno
- 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 }
ADVERTENCIA: Debido a que todos los entornos viven en un solo host, todos los libros de jugadas deben ejecutarse individualmente; de lo contrario, Ansible intentará ejecutar todos los scripts como el primer usuario de inicio de sesión ssh y solo usará las variables para el primer usuario. Si necesita ejecutar todos los scripts secuencialmente, use xargs para ejecutarlos cada uno 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: Las pruebas de ruta (es archivo, existe, ...) funcionan solo con rutas absolutas o rutas relativas al directorio de trabajo actual cuando se ejecuta el comando ansible-playbook. Esta es la razón por la que usamos la búsqueda. la búsqueda acepta rutas relativas al directorio del libro de jugadas y devuelve la ruta absoluta cuando existe el archivo.
O de una manera más yaml:
- 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 }}"
Es decir, en lugar de escribir una matriz en una línea con corchetes, como:
['path/to/file1', 'path/to/file2', ...]
Use la forma yaml de escribir valores de matriz en varias líneas, como:
- path/to/file1
- path/to/file2
Como se mencionó, esto busca un archivo vars llamado {{ ansible_hostname }}.yml
, y si no existe usadefault.yml
Nueva respuesta basada en las últimas versiones de Ansible: básicamente, debe usarla with_first_found
junto con skip: true
para omitir la tarea si no se encuentra ningún archivo.
- name: Include vars file if one exists meeting our condition.
include_vars: "{{ item }}"
with_first_found:
- files:
- vars/{{ variable_here }}.yml
skip: true
Esto hace que no tenga que tener un archivo vars alternativo en esa lista.
Ver relacionado: /programming//a/39544405/100134