Ansible: Comment supprimer des fichiers et des dossiers dans un répertoire?

152

Le code ci-dessous supprime uniquement le premier fichier qu'il obtient dans le répertoire Web. Je souhaite supprimer tous les fichiers et dossiers du répertoire Web et conserver le répertoire Web. Comment puis je faire ça?

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

Remarque: j'ai essayé d' rm -rfutiliser la commande et le shell, mais ils ne fonctionnent pas. Peut-être que je les utilise à tort.

Toute aide dans la bonne direction sera appréciée.

J'utilise ansible 2.1.0.0

Abbas
la source
On dirait un bug.
ceving

Réponses:

132

Le code ci-dessous supprimera tout le contenu de artifact_path

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

Remarque : cela supprimera également le répertoire.

Mohan Kumar P
la source
3
les citations ne sont pas requises. Ceci est mon code de travail uniquement. artifact_path est comme / app / my_app / work /
Mohan Kumar P
83
L'OP (et moi-même) voulons une solution qui supprimera le contenu du dossier MAIS PAS le dossier lui-même. Cette solution supprime le contenu ET le dossier lui-même.
stochastique
19
Comment cela a-t-il obtenu un vote favorable? Cela supprime également le répertoire.
deppfx
17
Quelqu'un a-t-il eu un échec du code ci-dessus avec artifact_path étant nul? On a l'impression que cela pourrait être sensible à l'un de ces grands rm -rf /moments de l'histoire
ted-k42
2
@ ted-k42 Je ferais quelque chose comme ça juste pour être sûr:when: artifact_path is defined and artifact_path != ""
bmaupin
69

Utilisation du module shell ( idempotent aussi):

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

Solution la plus propre si vous ne vous souciez pas de la date de création et du propriétaire / des autorisations:

- file: path=/home/mydata/web state=absent
- file: path=/home/mydata/web state=directory
bonjour
la source
7
Fonctionne mais n'a pas supprimé les fichiers commençant par. comme .htaccess
Abbas
Shell a également travaillé pour moi. Exactement la même tâche mais échangée shellcontre commandet cela fonctionne
SomethingOn
4
Les jokers ne fonctionneront pas avec la commande car ils nécessitent un shell pour l'expansion
JamesP
1
Notez que cela peut changer vos autorisations / propriétaire à moins que vous ne définissiez explicitement le moment de la création.
NeverEndingQueue
En utilisant le shell, vous recevrez un avertissement concernant l'utilisation du module de fichiers avec state = absent au lieu de shell rm. Pour éviter cela, ajoutez simplement des arguments: warn: false
Rodrigo
60

Supprimez le répertoire (essentiellement une copie de https://stackoverflow.com/a/38201611/1695680 ), Ansible fait cette opération avec rmtreesous le capot.

- 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 vous n'avez pas le luxe de supprimer tout le répertoire et de le recréer, vous pouvez le rechercher à la recherche de fichiers (et de répertoires) et de les supprimer un par un. Ce qui prendra du temps. Vous voulez probablement vous assurer que [ssh_connection]\npipelining = Truevotre fichier ansible.cfg est activé.

- 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
la source
6
La première tâche est la solution la plus élégante que j'ai vue. Notez les commentaires ailleurs qu'il y a une demande de fonctionnalité de longue date à ajouterstate=empty
William Turrell
24

Je n'ai vraiment pas aimé la solution rm, et ansible vous donne également des avertissements sur l'utilisation de rm. Voici donc comment le faire sans avoir besoin de rm et sans avertissements anonymes.

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

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

Cris
la source
pourtant la meilleure solution pour la question !!
Vsegar
18

essayez la commande ci-dessous, cela devrait fonctionner

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

- file: path=/some/dir/{{ item }} state=absent
  with_items: {{ contents.stdout_lines }}
Ganesan Srinivasan
la source
3
vous avez manqué d'échapper correctement à la dernière ligne avec {{,}} pour obtenirwith_items: "{{ contents.stdout_lines }}"
Valerio Crini
Il est dangereux d'utiliser lsla sortie pour obtenir les noms de fichiers car elle n'imprime pas correctement les noms de fichiers avec des caractères spéciaux tels que les retours à la ligne.
bfontaine
5

Création d'une implémentation globale remaniée et sûre à partir de tous les commentaires et suggestions:

# 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
la source
Je pense que vous manquez le registerpour plugin_dir_deleted, non?
Bob Vork
merci de l'avoir signalé. J'ai fait sortir ce morceau de code de l'un de mes playbooks et je l'ai rendu plus générique en termes de dénomination, mais j'ai oublié de remplacer deux noms de variables
Markus
1
Bon truc, mais je pense que l'état de la dernière tâche doit être défini sur "répertoire" plutôt que "présent".
Andrew Allaire
1
Vous devez utiliser le résultat de vos statistiques pour conserver les autorisations: owner from pw_name, group from gr_name et mode from mode.
DylanYoung
essayé owner: dir_to_delete.stat.pw_name, group: dir_to_delete.stat.gr_name mode: dir_to_delete.stat.modemais cela échoue avec ma version actuelle d'Ansible :(
Markus
3

En utilisant le fichier glob, cela fonctionnera également. Il y a une erreur de syntaxe dans le code que vous avez publié. J'ai modifié et testé cela devrait fonctionner.

- name: remove web dir contents
  file:
    path: "{{ item }}"
    state: absent
  with_fileglob:
    - "/home/mydata/web/*"
Deepali Mittal
la source
7
with_fileglobfonctionne uniquement sur une machine locale, pas distante; n'est-ce pas vrai?
Stepan Vavra
Vrai .. with_fileglob est pour local uniquement
Deepali Mittal
De plus, cela ne supprime pas les répertoires, seuls les fichiers sont supprimés.
vikas027
2

Alors qu'Ansible débat toujours de la mise en œuvre de 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 }}"

Notez cependant qu'avec la synchronisation, vous devriez quand même pouvoir synchroniser correctement vos fichiers (avec suppression).

Marcin
la source
2

C'est ce que je propose:

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

Tout d'abord, nous obtenons la liste des répertoires avec find, paramètre

  • file_typeà any, afin que nous ne manquions pas de répertoires et de liens imbriqués
  • hiddenà yes, pour ne pas sauter les fichiers cachés
  • également, ne définissez pas recursesur yes, car ce n'est pas seulement inutile, mais peut augmenter le temps d'exécution.

Ensuite, nous parcourons cette liste avec le filemodule. Sa sortie est un peu verbeuse, cela loop_control.labelnous aidera donc à limiter la sortie (vous trouverez ce conseil ici ).


Mais j'ai trouvé que la solution précédente était quelque peu lente, car elle itère à travers le contenu, alors je suis allé avec:

- 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 }}"
  • obtenir les propriétés du répertoire avec stat
  • supprimer le répertoire
  • recréez le répertoire avec les mêmes propriétés.

Cela me suffisait, mais vous pouvez également ajouter attributes, si vous le souhaitez.

Alexandre
la source
1

Il y a une question ouverte à ce sujet.

Pour l'instant, la solution fonctionne pour moi: créer un dossier vide localement et le synchroniser avec le dossier distant.

Voici un exemple de playbook:

- 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
la source
1

J'ai écrit un module ansible personnalisé pour nettoyer les fichiers en fonction de plusieurs filtres tels que l'âge, l'horodatage, les modèles globaux, etc.

Il est également compatible avec les anciennes versions. Il peut être trouvé ici .

Voici un exemple:

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

Je veux m'assurer que la commande find ne supprime que tout ce qui se trouve dans le répertoire et laisse le répertoire intact car dans mon cas, le répertoire est un système de fichiers. Le système générera une erreur en essayant de supprimer un système de fichiers mais ce n'est pas une bonne option. J'utilise l'option shell car c'est la seule option fonctionnelle que j'ai trouvée jusqu'à présent pour cette question.

Ce que j'ai fait:

Modifiez le fichier hosts pour y insérer des variables:

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

Et créez un playbook:

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

Cela supprimera tous les fichiers et répertoires dans le répertoire / système de fichiers de la variable COGNOS_HOME. L'option "-mindepth 1" garantit que le répertoire courant ne sera pas touché.

Tjerk Maij
la source
0

Juste un petit modèle de copier-coller plus propre de la réponse de ThorSummoners, si vous utilisez Ansible> = 2.3 (la distinction entre les fichiers et les répertoires n'est plus nécessaire.)

- 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
la source
-1

En supposant que vous soyez toujours sous Linux, essayez le findcmd.

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

Cela devrait effacer les fichiers / dossiers / cachés sous /home/mydata/web

Sherzod Odinaev
la source
1
Cela peut fonctionner, mais l'utilisation du module shell doit toujours être un dernier recours.
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
la source
-4

Ceci est mon exemple.

  1. Installer le référentiel
  2. Installer le package rsyslog
  3. arrêter rsyslog
  4. supprimer tous les fichiers dans / var / log / rsyslog /
  5. démarrer 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
la source
-6

Ci-dessous a travaillé pour moi,

- name: Ansible delete html directory
  file:
   path: /var/www/html
   state: directory
Sakharam Thorat
la source
Cela confirmera simplement que le répertoire existe. Il le créera s'il ne le fait pas, mais ne fera rien d'autre que signaler OK s'il le fait.
Chris