modules ansible ansible-template

modules - ansible-¿Eliminar archivos no administrados del directorio?



command ansible module (7)

Aparentemente esto no es posible con ansible en este momento. Tuve una conversación con mdehaan en IRC y todo se reduce a no poder tener un gráfico acíclico de recursos dirigido , lo que hace que esto sea muy difícil.

Al pedirle a mdehaan un ejemplo, por ejemplo, administrar con autoridad un directorio sudoers.d, se le ocurrieron estas cosas:

14:17 < mdehaan> Robe: http://pastebin.com/yrdCZB0y 14:19 < Robe> mdehaan: HM 14:19 < Robe> mdehaan: that actually looks relatively sane 14:19 < mdehaan> thanks :) 14:19 < Robe> the problem I''m seeing is that I''d have to gather the managed files myself 14:19 < mdehaan> you would yes 14:19 < mdehaan> ALMOST 14:20 < mdehaan> you could do a fileglob and ... well, it would be a little gross [..] 14:32 < mdehaan> eh, theoretical syntax, nm 14:33 < mdehaan> I could do it by writing a lookup plugin that filtered a list 14:34 < mdehaan> http://pastebin.com/rjF7QR24 14:34 < mdehaan> if that plugin existed, for instance, and iterated across lists in A that were also in B

Quiero copiar de forma recursiva sobre un directorio y renderizar todos los archivos .j2 allí como plantillas. Para esto estoy usando actualmente las siguientes líneas:

- template: > src=/src/conf.d/{{ item }} dest=/dest/conf.d/{{ item|replace(''.j2'','''') }} with_lines: find /src/conf.d/ -type f -printf "%P/n"

Ahora estoy buscando una manera de eliminar archivos no administrados de este directorio. Por ejemplo, si /src/conf.d/ un archivo / plantilla de /src/conf.d/ también quiero que Ansible lo elimine de /dest/conf.d/ .

Hay alguna manera de hacer esto? Intenté juguetear con rsync --delete , pero tengo un problema con las plantillas que eliminan su sufijo .j2 .


Aquí hay algo que se me ocurrió:

- template: src=/source/directory{{ item }}.j2 dest=/target/directory/{{ item }} register: template_results with_items: - a_list.txt - of_all.txt - templates.txt - set_fact: managed_files: "{{ template_results.results|selectattr(''invocation'', ''defined'')|map(attribute=''invocation.module_args.dest'')|list }}" - debug: var: managed_files verbosity: 0 - find: paths: "/target/directory/" patterns: "*.txt" register: all_files - set_fact: files_to_delete: "{{ all_files.files|map(attribute=''path'')|difference(managed_files) }}" - debug: var: all_files verbosity: 0 - debug: var: files_to_delete verbosity: 0 - file: path={{ item }} state=absent with_items: "{{ files_to_delete }}"

  • Esto genera las plantillas (como lo desee) y registra los resultados en ''template_results''
  • Los resultados se modifican para obtener una lista simple del "destino" de cada plantilla. Las plantillas omitidas (debido a una condición cuando no se muestra) no tienen un atributo de "invocación", por lo que se eliminan.
  • "buscar" se usa para obtener una lista de todos los archivos que deberían estar ausentes, a menos que se escriba específicamente.
  • luego se modifica para obtener una lista sin procesar de los archivos presentes, y luego se eliminan los archivos "supuestos para estar allí".
  • Los restantes "files_to_delete" se eliminan.

Pros: Evitas que se muestren varias entradas "omitidas" durante las eliminaciones.

Contras: deberá concatenar cada plantilla_resultados.resultados si desea realizar varias tareas de plantilla antes de realizar la búsqueda / eliminación.


Hacemos esto con nuestros archivos nginx, ya que queremos que estén en un orden especial, provienen de plantillas, pero eliminamos las que no están administradas, esto funciona:

# loop through the nginx sites array and create a conf for each file in order # file will be name 01_file.conf, 02_file.conf etc - name: nginx_sites conf template: > src=templates/nginx/{{ item.1.template }} dest={{ nginx_conf_dir }}/{{ ''%02d'' % item.0 }}_{{ item.1.conf_name|default(item.1.template) }} owner={{ user }} group={{ group }} mode=0660 with_indexed_items: nginx_sites notify: - restart nginx register: nginx_sites_confs # flatten and map the results into simple list # unchanged files have attribute dest, changed have attribute path - set_fact: nginx_confs: "{{ nginx_sites_confs.results|selectattr(''dest'', ''string'')|map(attribute=''dest'')|list + nginx_sites_confs.results|selectattr(''path'', ''string'')|map(attribute=''path'')|select|list }}" when: nginx_sites # get contents of conf dir - shell: ls -1 {{ nginx_conf_dir }}/*.conf register: contents when: nginx_sites # so we can delete the ones we don''t manage - name: empty old confs file: path="{{ item }}" state=absent with_items: contents.stdout_lines when: nginx_sites and item not in nginx_confs

El truco (como puede ver) es que la plantilla y with_items tienen diferentes atributos en los resultados del registro. Luego los convierte en una lista de archivos que administra y luego obtiene una lista del directorio y elimina los que no están en esa lista.

Se podría hacer con menos código si ya tiene una lista de archivos. Pero en este caso estoy creando una lista indexada, así que necesito crear la lista también con el mapa.


Lo haría de esta manera, asumiendo que una variable definida como ''archivos_del_archivos'' es una lista.

- shell: ls -1 /some/dir register: contents - file: path=/some/dir/{{ item }} state=absent with_items: contents.stdout_lines when: item not in managed_files


Por lo general, no -unmanaged archivos, pero -unmanaged sufijo no -unmanaged a su nombre. Ejemplos de tareas ansibles:

- name: Get sources.list.d files shell: grep -r --include=/*.list -L ''^# Ansible'' /etc/apt/sources.list.d || true register: grep_unmanaged changed_when: grep_unmanaged.stdout_lines - name: Add ''-unmanaged'' suffix shell: rename ''s/$/-unmanaged/'' {{ item }} with_items: grep_unmanaged.stdout_lines

EXPLICACIÓN

Usos del comando Grep:

  • -r hacer búsqueda recursiva
  • --include=/*.list - solo toma archivos con extensión .list durante la búsqueda recursiva
  • -L ''^# Ansible'' : muestra los nombres de archivos que no tienen una línea que comience por ''# Ansible''
  • || true || true - esto se usa para ignorar los errores. Los ignore_errors de Ansible también funcionan, pero antes de ignorar el error, ansible lo mostrará en color rojo durante la ejecución de ansible-playbook, que es indeseable (al menos para mí).

Luego registro la salida del comando grep como una variable. Cuando grep muestra cualquier salida, configuro esta tarea como modificada (la línea changed_when sea ​​responsable de esto).

En la siguiente tarea, itero la salida de grep (es decir, los nombres de archivo devueltos por grep) y ejecuto el comando rename para agregar un sufijo a cada archivo.

Eso es todo. La próxima vez que ejecute el comando, la primera tarea debe ser verde y la segunda omitida.


Puede haber un par de maneras de manejar esto, pero ¿sería posible vaciar completamente el directorio de destino en una tarea antes del paso de la plantilla? ¿O tal vez colocar los archivos de plantilla en un directorio temporal y luego eliminar + cambiar el nombre en un paso posterior?


Quiero compartir mi experiencia con este caso.

Ansible de la versión 2.2 tiene un bucle with_filetree que proporciona una forma sencilla de cargar dirs, enlaces, archivos estáticos e incluso (!) Plantillas. Es la mejor manera de mantener mi directorio de configuración sincronizado.

- name: etc config - Create directories file: path: "{{ nginx_conf_dir }}/{{ item.path }}" state: directory mode: 0755 with_filetree: etc/nginx when: item.state == ''directory'' - name: etc config - Creating configuration files from templates template: src: "{{ item.src }}" dest: "{{ nginx_conf_dir }}/{{ item.path | regex_replace(''//.j2$'', '''') }}" mode: 0644 with_filetree: etc/nginx when: - item.state == "file" - item.path | match(''.+/.j2$'') | bool - name: etc config - Creating staic configuration files copy: src: "{{ item.src }}" dest: "{{ nginx_conf_dir }}/{{ item.path }}" mode: 0644 with_filetree: etc/nginx when: - item.state == "file" - not (item.path | match(''.+/.j2$'') | bool) - name: etc config - Recreate symlinks file: src: "{{ item.src }}" dest: "{{ nginx_conf_dir }}/{{ item.path }}" state: link force: yes mode: "{{ item.mode }}" with_filetree: etc/nginx when: item.state == "link"

A continuación, es posible que desee eliminar los archivos no utilizados de config dir. Es sencillo. Recopilamos una lista de los archivos cargados y los archivos existentes en el servidor remoto, luego elimine la diferencia.

Pero podemos querer tener archivos no administrados en el directorio de configuración. He usado la funcionalidad de find de la -prune para evitar borrar carpetas con archivos no administrados.

PS _ (Y) _ seguro después de haber eliminado algunos archivos no administrados

- name: etc config - Gathering managed files set_fact: __managed_file_path: "{{ nginx_conf_dir }}/{{ item.path | regex_replace(''//.j2$'', '''') }}" with_filetree: etc/nginx register: __managed_files - name: etc config - Convert managed files to list set_fact: managed_files="{{ __managed_files.results | map(attribute=''ansible_facts.__managed_file_path'') | list }}" - name: etc config - Gathering exist files (excluding .ansible_keep-content dirs) shell: find /etc/nginx -mindepth 1 -type d -exec test -e ''{}/.ansible_keep-content'' /; -prune -o -print register: exist_files changed_when: False - name: etc config - Delete unmanaged files file: path="{{ item }}" state=absent with_items: "{{ exist_files.stdout_lines }}" when: - item not in managed_files