web-dev-qa-db-fra.com

ansible - supprimer les fichiers non gérés du répertoire?

Je veux copier récursivement sur un répertoire et rendre tous les fichiers . J2 dedans comme modèles. Pour cela, j'utilise actuellement les lignes suivantes:

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

Maintenant, je cherche un moyen de supprimer les fichiers non gérés de ce répertoire. Par exemple, si je supprime un fichier/modèle de /src/conf.d/ Je veux qu'Ansible le supprime de /dest/conf.d/ ainsi que.

Y a-t-il un moyen de le faire? J'ai essayé de jouer avec rsync --delete, mais là j'ai eu un problème avec les modèles qui ont leur suffixe .j2 supprimé.

41
Michael Krupp

Je le ferais comme ça, en supposant une variable définie comme 'managed_files' en haut qui est une liste.

- 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
49
user2645850

Nous le faisons avec nos fichiers nginx, car nous voulons qu'ils soient dans un ordre spécial, proviennent de modèles, mais supprimez ceux non gérés, cela fonctionne:

  # 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

L'astuce (comme vous pouvez le voir) est que le modèle et with_items ont des attributs différents dans les résultats du registre. Ensuite, vous les transformez en une liste de fichiers que vous gérez, puis obtenez une liste du répertoire et supprimez ceux qui ne figurent pas dans cette liste.

Pourrait être fait avec moins de code si vous avez déjà une liste de fichiers. Mais dans ce cas, je crée une liste indexée, je dois donc également créer la liste avec la carte.

11
dalore

Je veux partager mon expérience avec ce cas.

Ansible à partir de la 2.2 est la boucle with_filetree fournit un moyen simple de télécharger des répertoires, des liens, des fichiers statiques et même des modèles (!). C'est le meilleur moyen de garder mon répertoire de configuration synchronisé.

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

Ensuite, nous souhaitons peut-être supprimer les fichiers inutilisés du répertoire de configuration. C'est simple. Nous recueillons la liste des fichiers téléchargés et les fichiers existent sur le serveur distant, supprimez ensuite la différence.

Mais nous souhaitons peut-être avoir des fichiers non gérés dans le répertoire de configuration. J'ai utilisé -Prune fonctionnalité de find pour éviter d'effacer les dossiers contenant des fichiers non gérés.

PS _ (Y) _ sûr après avoir supprimé certains fichiers non gérés

- 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
5
dmOx

Voici quelque chose que j'ai trouvé:

 - modèle: src =/source/répertoire {{item}}. j2 dest =/target/directory/{{item}} 
 registre: 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 
 verbosité: 0 
 
 - rechercher: 
 chemins: "/target/directory/"
 modèles:" * .txt "
 registre: all_files 
 - set_fact: 
 files_to_delete: "{{all_files.files | map (attribute = 'path') | difference (managed_files)}}" 
 
 - débogage: 
 var: all_files 
 verbosité: 0 
 - débogage: 
 var: files_to_delete 
 verbosité: 0 
 
 - fichier: path = {{item}} state = absent 
 with_items: "{{files_to_delete}}" 
  • Cela génère les modèles (comme vous le souhaitez) et enregistre les résultats dans 'template_results'
  • Les résultats sont modifiés pour obtenir une liste simple du "dest" de chaque modèle. Les modèles ignorés (en raison d'une condition when, non illustrée) n'ont pas d'attribut "invocation", ils sont donc filtrés.
  • "find" est ensuite utilisé pour obtenir une liste de tous les fichiers qui devraient être absents à moins qu'ils ne soient spécifiquement écrits.
  • celui-ci est ensuite modifié pour obtenir une liste brute des fichiers présents, puis les fichiers "supposés être là" sont supprimés.
  • Les "files_to_delete" restants sont ensuite supprimés.

Avantages: vous évitez que plusieurs entrées "ignorées" n'apparaissent lors des suppressions.

Inconvénients: vous devrez concaténer chaque template_results.results si vous souhaitez effectuer plusieurs tâches de modèle avant de rechercher/supprimer.

3
Chris Cogdon

Il peut y avoir deux façons de gérer cela, mais serait-il possible de vider entièrement le répertoire cible dans une tâche avant l'étape du modèle? Ou peut-être déposer les fichiers modèles dans un répertoire temporaire, puis supprimer + renommer dans une étape ultérieure?

2
Tybstar

Habituellement, je ne supprime pas les fichiers mais j'ajoute -unmanaged suffixe à son nom. Exemples de tâches 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

EXPLICATION

La commande Grep utilise:

  • -r pour effectuer une recherche récursive
  • --include=\*.list - ne prend que les fichiers avec l'extension .list pendant la recherche récursive
  • -L '^# Ansible' - affiche les noms de fichiers sans ligne commençant par '# Ansible'
  • || true - ceci est utilisé pour ignorer les erreurs. ignore_errors fonctionne également mais avant d'ignorer l'erreur, ansible l'affichera en rouge lors de l'exécution de ansible-playbook, ce qui n'est pas souhaité (du moins pour moi).

Ensuite, j'enregistre la sortie de la commande grep en tant que variable. Lorsque grep affiche une sortie, je définis cette tâche comme modifiée (la ligne changed_when en est responsable).

Dans la tâche suivante, j'itère la sortie grep (c'est-à-dire les noms de fichiers retournés par grep) et exécute la commande rename pour ajouter un suffixe à chaque fichier.

C'est tout. La prochaine fois que vous exécutez la commande, la première tâche doit être verte et la seconde ignorée.

1
ahes

Apparemment, cela n'est pas possible avec ansible pour le moment. J'ai eu une conversation avec mdehaan sur IRC et cela se résume à ansible n'ayant pas graphique acyclique dirigé pour les ressources, rendant les choses comme ça très difficiles.

Demander à mdehaan un exemple, par exemple faisant autorité avec un répertoire sudoers.d, il a trouvé ces choses:

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
0
Michael Renner