Cómo crear archivos de configuración dinámicos utilizando plantillas de Ansible

En el artículo anterior de esta serie, 8 pasos para desarrollar un rol de Ansible en Linux, creé un Rol responsable para instalar Vim y configurarlo con algunos complementos y una estática vimrc archivo de configuración.

Este artículo mejora esta función al reemplazar este archivo de configuración estático con un archivo más flexible, generado dinámicamente usando Ansible. modelo.

Los modelos de Ansible le permiten crear archivos dinámicamente mediante la interpolación de variables o el uso de expresiones lógicas como condiciones y bucles. Es útil para definir archivos de configuración que se adapten a diferentes contextos sin tener que gestionar archivos adicionales. Por ejemplo, puede crear un /etc/hosts archivo que contiene la dirección IP del nodo actual. Luego puede ejecutar el libro de jugadas en diferentes hosts, lo que genera diferentes archivos, uno para cada host único.

El motor de modelo de Ansible utiliza Jinja2 lenguaje de plantilla, un lenguaje de plantilla popular para el ecosistema de Python. Jinja le permite interpolar variables y expresiones con texto normal usando caracteres especiales como { y {%. Al hacer esto, puede mantener la mayor parte del archivo de configuración como texto sin formato e inyectar lógica solo cuando sea necesario, lo que facilita la creación, comprensión y mantenimiento de archivos de plantilla.

Puede usar este lenguaje de plantilla en todos los playbooks de Ansible, pero para crear instancias de archivos de configuración basados ​​en plantillas, use el modelo módulo. Este módulo funciona de la misma manera que el Copiar módulo pero, en lugar de copiar un archivo predefinido, primero representa el archivo de plantilla en función de su lógica integrada y luego lo copia en el host de destino. Este módulo es idempotente y solo reemplaza el archivo si el contenido del objetivo no coincide con el contenido del modelo renderizado.

Este ejemplo se basa en el rol desarrollado en el artículo anterior. Si no lo tienes, puedes encontrar los archivos originales en este depositar.

Índice

    Definir un modelo

    Comience por crear un directorio de plantillas. Cambiar a la vim directorio de roles y crear un nuevo subdirectorio, templates. Esto no es estrictamente necesario, pero Ansible busca archivos de plantilla en este subdirectorio de forma predeterminada, lo que facilita su uso sin especificar una ruta completa:

    $ cd roles/vim
    $ mkdir templates
    $ ls
    defaults  files  handlers  meta  molecule  README.md  tasks  templates  tests  vars

    Luego cambie al directorio recién creado y edite un nuevo archivo de plantilla. Por convención, nombre el archivo de plantilla con el nombre del archivo de destino y el .j2 extensión. En este ejemplo, dado que está modelando el archivo de configuración de Vim .vimrc, el nombre del modelo es vimrc.j2:

    $ cd templates
    $ vim vimrc.j2

    Agregue las líneas de configuración estática básica en la parte superior del archivo:

    execute pathogen#infect()
    syntax on
    filetype plugin indent on

    Estas líneas iniciales son siempre estáticas y siempre serán las mismas para cada despliegue. A continuación, interpolemos algunas variables para generar una configuración dinámica.

    Usando variables

    La forma principal de personalizar un modelo es interpolar variables. Agregue un marcador de posición para una variable proporcionando el nombre de la variable entre los pares de llaves {{ }}. Al renderizar el modelo, Ansible reemplaza la expresión completa con el valor de la variable. Por ejemplo, defina una configuración dinámica de Vim, que permita al usuario especificar el esquema de color deseado usando la variable color_scheme, así:

    colo {{ color_scheme }}

    Usa otra variable, fzf_preview, para especificar el tipo de ventana de vista previa para el complemento FZF:

    " Configuration Vim.FZF
    let g:fzf_preview_window = '{{ fzf_preview }}'
    let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6  }  }
    
    " Configuration NERDTree
    map <F5> :NERDTreeToggle<CR>

    El uso de variables brinda la flexibilidad para cumplir con múltiples requisitos, pero Model Engine puede hacer aún más. A continuación, creemos un bloque condicional.

    Configuración condicional

    En algunos casos, las variables no son suficientes para hacer lo que necesita. Por ejemplo, imagine que desea incluir un bloque de texto en el archivo de configuración solo bajo ciertas condiciones. El motor de modelo proporciona expresiones más complejas, como if condiciones Añadir estas condiciones delimitadas por {% %}. Por ejemplo, puede incluir líneas de configuración de líneas aéreas en su .vimrc archivo, pero sólo si el vim-airline el complemento está en la lista de complementos para instalar:

    {% if 'vim-airline' in plugins | map(attribute="name") | list %}
    " Configuration vim Airline
    set laststatus=2
    
    let g:airline#extensions#tabline#enabled=1
    let g:airline_powerline_fonts=1
    {% endif %}

    En este caso, el if condición busca el nombre vim-airline en la lista de nombres de complementos extraídos de la variable plugins utilizando el map filter. Para obtener más información sobre los filtros de Ansible, consulte la Documentación.

    Usar datos de Ansible

    Además de las variables que establece directamente en el rol o libro de jugadas, también puede personalizar sus plantillas utilizando los datos recopilados de los hosts mediante Ansible. los hechos. Los datos están disponibles en el ansible_facts diccionario donde cada clave representa datos recopilados del sistema de destino.

    Este ejemplo configura el flotador complemento de shell como shell definido por el usuario en la máquina de destino:

    " Configuration floaterm
    let g:floaterm_shell="{{ ansible_facts["user_shell"] }} --login"

    Este es un recurso poderoso que le permite generar automáticamente una configuración adecuada para cada host.

    en bucle

    El último recurso que utilizará en este ejemplo es for rizado. Los bucles le permiten iterar a través de una lista o diccionario y hacer algo por cada elemento encontrado. Este caso permite a los usuarios proporcionar un diccionario de opciones adicionales que deseen utilizar para configurar flotador y establezca una línea de configuración para cada uno, así:

    {% for opt in floaterm_options %}
    let g:{{ opt }} = {{ floaterm_options[opt] }}
    {% endfor %}

    En este caso, floatterm_opciones es un diccionario de opciones definido con una clave y un valor. Para cada iteración del bucle, el motor de plantillas asigna la clave a la variable opt. Puedes usarlo directamente en el for bloquear o usarlo para extraer valor usando notación de diccionario floaterm_options[opt].

    Establecer valores predeterminados para las variables

    Ha terminado de definir el modelo. Todo el modelo se ve así:

    execute pathogen#infect()
    syntax on
    filetype plugin indent on
    
    colo {{ color_scheme }}
    
    " Configuration Vim.FZF
    let g:fzf_preview_window = '{{ fzf_preview }}'
    let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6  }  }
    
    " Configuration NERDTree
    map <F5> :NERDTreeToggle<CR>
    
    {% if 'vim-airline' in plugins | map(attribute="name") | list %}
    " Configuration vim Airline
    set laststatus=2
    
    let g:airline#extensions#tabline#enabled=1
    let g:airline_powerline_fonts=1
    {% endif %}
    
    " Configuration floaterm
    let g:floaterm_shell="{{ ansible_facts["user_shell"] }} --login"
    
    {% for opt in floaterm_options %}
    let g:{{ opt }} = {{ floaterm_options[opt] }}
    {% endfor %}

    Guarde y cierre este archivo, luego edite el archivo de variables predeterminado defaults/main.yml para definir valores por defecto para estas variables en caso de que el usuario no los especifique:

    ---
    # defaults file for vim
    color_scheme: darkblue
    floaterm_options:
      floaterm_width: 0.9
      floaterm_height: 0.9
      floaterm_keymap_toggle: "'<F12>'"
    fzf_preview: "right:50%"
    plugins:
      - name: vim-airline
        url: https://github.com/vim-airline/vim-airline
      - name: nerdtree
        url: https://github.com/preservim/nerdtree
      - name: fzf-vim
        url: https://github.com/junegunn/fzf.vim
      - name: vim-gitgutter
        url: https://github.com/airblade/vim-gitgutter
      - name: vim-fugitive
        url: https://github.com/tpope/vim-fugitive
      - name: vim-floaterm
        url: https://github.com/voldikss/vim-floaterm

    En este caso, si el usuario no especifica el esquema de color, el rol usa azul oscuro por defecto. Esta es una buena manera de proporcionar una configuración lista para usar, al mismo tiempo que permite al usuario realizar cambios cuando sea necesario.

    Guarde y cierre el archivo de variables predeterminado. A continuación, asegúrese de que el rol utilice el archivo de plantilla.

    Edite el archivo de tareas para usar la plantilla

    Ahora que tiene listo su archivo de plantilla y las variables predeterminadas, utilícelas en su rol actualizando la tarea. Ensure .vimrc config in place en el archivo tasks/main.yml usar el modelo módulo en lugar de Copiar módulo. Asegúrate que origen el nombre del modelo corresponde al archivo del modelo con el .j2 extensión:

    ---
    - name: Ensure .vimrc config in place
      template:
        src: vimrc.j2
        dest: "{{ vimrc }}"
        backup: true
        mode: 0640

    Esta es la única modificación de trabajo requerida. El rol realiza todas las demás tareas de la misma manera y, al final, representa la plantilla y usa el archivo resultante como el archivo de configuración de Vim.

    Ejecutar el libro de jugadas

    Ahora pruebe su rol ejecutando el libro de jugadas usando el ansible-playbook comando y el nombre del libro de jugadas, de la misma manera que lo ejecutó en el artículo anterior. Si ha ejecutado este libro de jugadas con el vigor role antes, modificará el archivo de configuración solo si es necesario. Si es la primera vez que lo ejecuta, realizará todas las tareas.

    Notar: Guardar uno existente .vimrc archivo de configuración antes de ejecutar este libro de jugadas:

    $ cd ../..
    $ ansible-playbook -K vim-config.yaml

    Verifique el archivo de configuración resultante para ver el modelo renderizado:

    $ cat $HOME/.vimrc
    execute pathogen#infect()
    syntax on
    filetype plugin indent on
    
    colo darkblue
    
    " Configuration Vim.FZF
    let g:fzf_preview_window = 'right:50%'
    let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6  }  }
    
    " Configuration NERDTree
    map <F5> :NERDTreeToggle<CR>
    
    " Configuration vim Airline
    set laststatus=2
    
    let g:airline#extensions#tabline#enabled=1
    let g:airline_powerline_fonts=1
    
    " Configuration floaterm
    let g:floaterm_shell="/bin/bash --login"
    let g:floaterm_width = 0.9
    let g:floaterm_height = 0.9
    let g:floaterm_keymap_toggle="<F12>"

    Puedes ejecutar el libro de jugadas, vim-config.yaml, nuevamente, modificando algunas variables para ver el efecto en el archivo de configuración. Por ejemplo, elimine el complemento vim-airline en la lista y cambie el esquema de color a industria:

    ---
    - name: Config Vim with plugins
      hosts: localhost
      gather_facts: true
      become: false
    
      tasks:
        - name: Configure Vim using role
          import_role:
            name: vim
          vars:
            color_scheme: industry
            plugins:
              - name: nerdtree
                url: https://github.com/preservim/nerdtree
              - name: fzf-vim
                url: https://github.com/junegunn/fzf.vim
              - name: vim-gitgutter
                url: https://github.com/airblade/vim-gitgutter
              - name: vim-fugitive
                url: https://github.com/tpope/vim-fugitive
              - name: vim-floaterm
                url: https://github.com/voldikss/vim-floaterm
    

    Guarda el libro de jugadas y ejecútalo de nuevo:

    $ ansible-playbook -K vim-config.yaml

    El nuevo archivo de configuración ya no tiene la configuración de la línea aérea:

    $ cat $HOME/.vimrc
    execute pathogen#infect()
    syntax on
    filetype plugin indent on
    
    colo industry
    
    " Configuration Vim.FZF
    let g:fzf_preview_window = 'right:50%'
    let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6  }  }
    
    " Configuration NERDTree
    map <F5> :NERDTreeToggle<CR>
    
    " Configuration floaterm
    let g:floaterm_shell="/bin/bash --login"
    let g:floaterm_width = 0.9
    let g:floaterm_height = 0.9
    let g:floaterm_keymap_toggle="<F12>"

    ¿Y después?

    Una de las funciones más potentes de Ansible es la creación de modelos. Le permite definir una configuración personalizable y dinámica que se adapta a cada máquina de destino mientras ejecuta el libro de jugadas. Puede administrar archivos de configuración para cientos de máquinas de destino en un solo archivo o en un pequeño grupo de archivos mediante plantillas. Esto hace que sus roles sean más flexibles y fáciles de administrar.

    Este artículo ha cubierto la funcionalidad básica del motor de plantillas, y puede recorrer un largo camino usando solo esas funciones. El lenguaje de modelos Jinja2 proporciona muchas otras características que pueden ayudarlo a crear modelos extensibles y adaptables para una variedad de necesidades. Asegúrese de revisar su Documentación para más detalles.

    Para obtener más información sobre Ansible, consulte su documentos oficiales.

    Artículos de interés

    Subir