Ansible: ¿Cómo eliminar archivos y carpetas dentro de un directorio?

152

El siguiente código solo elimina el primer archivo que se encuentra dentro del directorio web. Quiero eliminar todos los archivos y carpetas dentro del directorio web y conservar el directorio web. ¿Cómo puedo hacer eso?

  - name: remove web dir contents
     file: path='/home/mydata/web/{{ item }}' state=absent
     with_fileglob:
       - /home/mydata/web/*

Nota: He intentado rm -rfusar el comando y el shell, pero no funcionan. Quizás los estoy usando mal.

Cualquier ayuda en la dirección correcta será apreciada.

Estoy usando ansible 2.1.0.0

Abbas
fuente
Parece un error
ceving

Respuestas:

132

El siguiente código eliminará todo el contenido de artifact_path

- name: Clean artifact path
  file:
    state: absent
    path: "{{ artifact_path }}/"

Nota : esto también eliminará el directorio.

Mohan Kumar P
fuente
3
No se requieren cotizaciones. Este es solo mi código de trabajo. artifact_path es como / app / my_app / work /
Mohan Kumar P
83
El OP (y yo) queremos una solución que elimine el contenido de la carpeta PERO NO la carpeta en sí. Esta solución elimina el contenido Y la carpeta en sí.
estocástico
19
¿Cómo obtuvo esto un voto a favor? Esto también elimina el directorio.
deppfx
17
¿Alguien ha fallado en el código anterior con artifact_path siendo nulo? rm -rf /
Parece
2
@ ted-k42 Haría algo como esto solo para estar seguro:when: artifact_path is defined and artifact_path != ""
bmaupin
69

Usando el módulo de shell ( también idempotente ):

- shell: /bin/rm -rf /home/mydata/web/*

Solución más limpia si no le importa la fecha de creación y el propietario / permisos:

- file: path=/home/mydata/web state=absent
- file: path=/home/mydata/web state=directory
hola
fuente
77
Funciona pero no eliminó los archivos a partir de. como .htaccess
Abbas
Shell también trabajó para mí. Misma tarea exacta, pero cambió shellpor commandy funciona
SomethingOn
44
Los comodines no funcionarán con el comando, ya que requieren un shell para la expansión
JamesP
1
Tenga en cuenta que esto podría cambiar sus permisos / propietario a menos que establezca explícitamente durante el momento de creación.
NeverEndingQueue
Al usar shell , recibirá una advertencia sobre el uso del módulo de archivo con state = ausente en lugar de shell rm. Para evitarlo, simplemente agregue args: warn: false
Rodrigo
60

Elimine el directorio (básicamente una copia de https://stackoverflow.com/a/38201611/1695680 ), Ansible realiza esta operación rmtreebajo el capó.

- name: remove files and directories
  file:
    state: "{{ item }}"
    path: "/srv/deleteme/"
    owner: 1000  # set your owner, group, and mode accordingly
    group: 1000
    mode: '0777'
  with_items:
    - absent
    - directory

Si no tiene el lujo de eliminar todo el directorio y volver a crearlo, puede escanearlo en busca de archivos (y directorios) y eliminarlos uno por uno. Lo que llevará un tiempo. Probablemente quiera asegurarse de tener [ssh_connection]\npipelining = Trueen su ansible.cfg encendido.

- block:
  - name: 'collect files'
    find:
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      # file_type: any  # Added in ansible 2.3
    register: collected_files

  - name: 'collect directories'
    find:
      paths: "/srv/deleteme/"
      hidden: True
      recurse: True
      file_type: directory
    register: collected_directories

  - name: remove collected files and directories
    file:
      path: "{{ item.path }}"
      state: absent
    with_items: >
      {{
        collected_files.files
        + collected_directories.files
      }}
ThorSummoner
fuente
66
La primera tarea es la solución más elegante que he visto. Tenga en cuenta los comentarios en otra parte que hay una solicitud de función de larga duración para agregarstate=empty
William Turrell
24

Realmente no me gustó la solución rm, también ansible te da advertencias sobre el uso de rm. Así que aquí es cómo hacerlo sin la necesidad de rm y sin advertencias ansibles.

- hosts: all
  tasks:
  - name: Ansible delete file glob
    find:
      paths: /etc/Ansible
      patterns: "*.txt"
    register: files_to_delete

  - name: Ansible remove file glob
    file:
      path: "{{ item.path }}"
      state: absent
    with_items: "{{ files_to_delete.files }}"

fuente: http://www.mydailytutorials.com/ansible-delete-multiple-files-directories-ansible/

Cris
fuente
¡Sin embargo, la mejor solución para la pregunta!
Vsegar
18

prueba el siguiente comando, debería funcionar

- shell: ls -1 /some/dir
  register: contents

- file: path=/some/dir/{{ item }} state=absent
  with_items: {{ contents.stdout_lines }}
Ganesan Srinivasan
fuente
3
te perdiste para escapar correctamente la última línea con {{,}} para obtenerwith_items: "{{ contents.stdout_lines }}"
Valerio Crini
Es peligroso usar ls'output para obtener nombres de archivos porque no imprime correctamente nombres de archivos con caracteres especiales como líneas nuevas.
bfontaine
5

Creé una implementación general revisada y segura de todos los comentarios y sugerencias:

# collect stats about the dir
- name: check directory exists
  stat:
    path: '{{ directory_path }}'
  register: dir_to_delete

# delete directory if condition is true
- name: purge {{directory_path}}
  file:
    state: absent
    path: '{{ directory_path  }}'
  when: dir_to_delete.stat.exists and dir_to_delete.stat.isdir

# create directory if deleted (or if it didn't exist at all)
- name: create directory again
  file:
    state: directory
    path: '{{ directory_path }}'
  when: dir_to_delete is defined or dir_to_delete.stat.exist == False
Markus
fuente
Creo que te estás perdiendo el registerpara plugin_dir_deleted, ¿verdad?
Bob Vork
Gracias por señalar esto. Tomé este código de uno de mis libros de jugadas y lo hice más genérico en términos de nomenclatura, pero olvidé reemplazar dos nombres de variables
Markus el
1
Cosas buenas, pero creo que el estado en la última tarea debe establecerse en "directorio" en lugar de "presente".
Andrew Allaire
1
Debe usar el resultado de su estadística para conservar los permisos: propietario de pw_name, grupo de gr_name y modo de modo.
DylanYoung
intentado owner: dir_to_delete.stat.pw_name, group: dir_to_delete.stat.gr_name mode: dir_to_delete.stat.modepero me falla con mi versión actual de Ansible :(
Markus
3

Usando file glob también funcionará. Hay algún error de sintaxis en el código que publicó. He modificado y probado esto debería funcionar.

- name: remove web dir contents
  file:
    path: "{{ item }}"
    state: absent
  with_fileglob:
    - "/home/mydata/web/*"
Deepali Mittal
fuente
77
with_fileglobfunciona solo en máquinas locales, no remotas; no es verdad?
Stepan Vavra
Es cierto .. with_fileglob es solo para locales
Deepali Mittal
Además, esto no elimina directorios, solo se eliminan los archivos.
vikas027
2

Si bien Ansible aún está debatiendo implementar state = empty https://github.com/ansible/ansible-modules-core/issues/902

my_folder: "/home/mydata/web/"
empty_path: "/tmp/empty"


- name: "Create empty folder for wiping."
  file:
    path: "{{ empty_path }}" 
    state: directory

- name: "Wipe clean {{ my_folder }} with empty folder hack."
  synchronize:
    mode: push

    #note the backslash here
    src: "{{ empty_path }}/" 

    dest: "{{ nl_code_path }}"
    recursive: yes
    delete: yes
  delegate_to: "{{ inventory_hostname }}"

Sin embargo, tenga en cuenta que, con la sincronización, debería poder sincronizar sus archivos (con eliminar) de todos modos.

Marcin
fuente
2

Eso es lo que se me ocurre:

- name: Get directory listing
  find:
    path: "{{ directory }}" 
    file_type: any
    hidden: yes
  register: directory_content_result

- name: Remove directory content
  file:
    path: "{{ item.path }}" 
    state: absent
  with_items: "{{ directory_content_result.files }}" 
  loop_control:
    label: "{{ item.path }}" 

Primero, estamos obteniendo una lista de directorios con find, estableciendo

  • file_typea any, para que no nos perdamos los directorios y enlaces anidados
  • hiddena yes, para no omitir archivos ocultos
  • También, no se ajusta recursea yes, ya que no sólo es innecesario, pero puede aumentar el tiempo de ejecución.

Luego, revisamos esa lista con el filemódulo. Su salida es un poco detallada, por loop_control.labello que nos ayudará a limitar la salida (encontré este consejo aquí ).


Pero encontré que la solución anterior era algo lenta, ya que itera a través del contenido, así que seguí con:

- name: Get directory stats
  stat:
    path: "{{ directory }}"
  register: directory_stat

- name: Delete directory
  file:
    path: "{{ directory }}"
    state: absent

- name: Create directory
  file:
    path: "{{ directory }}"
    state: directory
    owner: "{{ directory_stat.stat.pw_name }}"
    group: "{{ directory_stat.stat.gr_name }}"
    mode: "{{ directory_stat.stat.mode }}"
  • obtener propiedades de directorio con el stat
  • eliminar directorio
  • recrear directorio con las mismas propiedades.

Eso fue suficiente para mí, pero también puede agregar attributes, si lo desea.

Alejandro
fuente
1

Hay un problema abierto con respecto a esto.

Por ahora, la solución funciona para mí: crear una carpeta vacía localmente y sincronizarla con la remota.

Aquí hay un libro de jugadas de muestra:

- name: "Empty directory"
  hosts: *
  tasks:
    - name: "Create an empty directory (locally)"
      local_action:
        module: file
        state: directory
        path: "/tmp/empty"

    - name: Empty remote directory
      synchronize:
        src: /tmp/empty/
        dest: /home/mydata/web/
        delete: yes
        recursive: yes
w1100n
fuente
1

He escrito un módulo ansible personalizado para limpiar archivos basado en múltiples filtros como antigüedad, marca de tiempo, patrones globales, etc.

También es compatible con versiones anteriores ansibles. Se puede encontrar aquí .

Aquí hay un ejemplo:

- cleanup_files:
  path_pattern: /tmp/*.log
  state: absent
  excludes:
    - foo*
    - bar*
Rahul
fuente
0

Quiero asegurarme de que el comando find solo elimine todo dentro del directorio y deje el directorio intacto porque en mi caso el directorio es un sistema de archivos. El sistema generará un error al intentar eliminar un sistema de archivos, pero esa no es una buena opción. Estoy usando la opción de shell porque esa es la única opción de trabajo que encontré hasta ahora para esta pregunta.

Lo que hice:

Edite el archivo de hosts para incluir algunas variables:

[all:vars]
COGNOS_HOME=/tmp/cognos
find=/bin/find

Y crea un libro de jugadas:

- hosts: all
  tasks:
  - name: Ansible remove files
    shell: "{{ find }} {{ COGNOS_HOME }} -xdev -mindepth 1 -delete"

Esto eliminará todos los archivos y directorios en el directorio / sistema de archivos variable COGNOS_HOME. La opción "-mindepth 1" asegura que no se toque el directorio actual.

Tjerk Maij
fuente
0

Solo una pequeña y limpia plantilla de copiar y pegar de ThorSummoners responde, si está usando Ansible> = 2.3 (la distinción entre archivos y directorios ya no es necesaria).

- name: Collect all fs items inside dir
  find:
    path: "{{ target_directory_path }}"
    hidden: true
    file_type: any
  changed_when: false
  register: collected_fsitems
- name: Remove all fs items inside dir
  file:
    path: "{{ item.path }}"
    state: absent
  with_items: "{{ collected_fsitems.files }}"
  when: collected_fsitems.matched|int != 0
Enno Gröper
fuente
-1

Suponiendo que siempre estés en Linux, prueba el findcmd.

- name: Clean everything inside {{ item }}
  shell: test -d {{ item }} && find {{ item }} -path '{{ item }}/*' -prune -exec rm -rf {} \;
  with_items: [/home/mydata/web]

Esto debería borrar archivos / carpetas / ocultos debajo de /home/mydata/web

Sherzod Odinaev
fuente
1
Puede funcionar, pero el uso del módulo de shell siempre debe ser el último recurso.
Chris
-1
先 删除 对应 的 目录 , 然后 在 创建 该 目录 , 使用 的 是 嵌套 循环
  - name: delete old data and clean cache
    file:
      path: "{{ item[0] }}" 
      state: "{{ item[1] }}"
    with_nested:
      - [ "/data/server/{{ app_name }}/webapps/", "/data/server/{{ app_name }}/work/" ]
      - [ "absent", "directory" ]
    ignore_errors: yes
lanni654321
fuente
-4

Este es mi ejemplo.

  1. Instalar repositorio
  2. Instale el paquete rsyslog
  3. detener rsyslog
  4. eliminar todos los archivos dentro de / var / log / rsyslog /
  5. iniciar rsyslog

    - hosts: all
      tasks:
        - name: Install rsyslog-v8 yum repo
          template:
            src: files/rsyslog.repo
            dest: /etc/yum.repos.d/rsyslog.repo
    
        - name: Install rsyslog-v8 package
          yum:
            name: rsyslog
            state: latest
    
        - name: Stop rsyslog
          systemd:
            name: rsyslog
            state: stopped
    
        - name: cleann up /var/spool/rsyslog
          shell: /bin/rm -rf /var/spool/rsyslog/*
    
        - name: Start rsyslog
          systemd:
            name: rsyslog
            state: started
    
Satish
fuente
-6

A continuación funcionó para mí

- name: Ansible delete html directory
  file:
   path: /var/www/html
   state: directory
Sakharam Thorat
fuente
Esto solo confirmará que el directorio existe. Lo creará si no lo hace, pero no hará nada más que informar OK si lo hace.
Chris