Ansible: ¿Puedo usar vars_files cuando algunos archivos no existen?


17

Esa es la parte:

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

Si vars/vars.ymlno existe un archivo , aquí hay un error.

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

¿Cómo puedo cargar variables adicionales de este archivo solo si existe? (sin errores)

Respuestas:


27

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

44
Según los desarrolladores de Ansible , esta solución cargará todos los archivos, no solo el primero encontrado.
— tjanez

10

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_filespalabra clave del idioma.


"solo se encontró el primer archivo" - la idea era redefinir algunas variables, no todas
— Sergey

@Sergey, leyendo de nuevo tu pregunta, veo que lo que querías es un poco diferente. Gracias por señalar esto. Dejaré la respuesta tal como está si alguien más lo encuentra útil.
— tjanez

1
excepto que include_varsen la tarea dará una alta precedencia de variables en comparación con el rol defaultsovars
— Alex F

2

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

ansible.cfg

[defaults]
hash_behaviour=merge ;; merge rather than replace dictionaries http://docs.ansible.com/ansible/intro_configuration.html###hash-behaviour

Diseño de directorio ansible

/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

roles / desplegar / tareas / incluye.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"

group_vars / all.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

roles / deploy / vars / main.yml

valores predeterminados del proyecto

ansible_project:
  node_env:   development
  node_port:  4200
  nginx_port: 4400

roles / deploy / vars / project_1.yml

valores predeterminados para proyecto_1

ansible_project:
  node_port:  4201
  nginx_port: 4401

roles / deploy / vars / live / main.yml

valores predeterminados para el entorno en vivo, anula los valores predeterminados del proyecto

ansible_project:
  node_env: production

roles / deploy / vars / live / project_1.yml

anulaciones finales para project_1 en el entorno en vivo

ansible_project:
  nginx_port: 80

playbooks / demo.yml

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

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

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.


0

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


Esta respuesta usa el mismo código que este, excepto que usa datos diferentes. Es decir {{ ansible_hostname }}.yml, nombre de archivo en lugar de ../path/to/file1. ¿Cuál es el punto de? Se puede agregar un número ilimitado de nombres de archivos de entrada.
— techraf

@techraf: Ok, agregué algunas aclaraciones / amplificaciones sobre por qué se envió una nueva respuesta. Esto se debe a que los comentarios por defecto del servidor no admiten fragmentos de código de varias líneas, y solo estaba señalando que las matrices yaml se escriben con frecuencia (¿preferiblemente?) En varias líneas. También estaría bien si se editara la respuesta anterior y se mostrara el formato de matriz de varias líneas, como lo veo con más frecuencia. Entonces mi respuesta puede ser eliminada.
— Donn Lee

Ambas anotaciones se especifican en los documentos de Ansible en un capítulo Conceptos básicos de YAML . El hecho de que vea uno más a menudo que el otro todavía no hace que esta sea una nueva respuesta.
— techraf

0

Uniendo varias piezas juntas ... include_vars con una cláusula when que es verdadera cuando existe el archivo. es decir

vars:
  file_to_include: /path/to/file
tasks:
  - include_vars: "{{ file_to_include }}"
    when: file_to_include is exists

0

Nueva respuesta basada en las últimas versiones de Ansible: básicamente, debe usarla with_first_foundjunto con skip: truepara 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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.