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

je veux recursivement copier sur un répertoire et rendu .j2 les fichiers qui s'y trouvent sont des modèles. Pour cela, je suis actuellement en utilisant 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 "%Pn"

maintenant je cherche un moyen de supprimer les fichiers non gérés de ce répertoire. Par exemple si je supprime un fichier/template de /src/conf.d/ je veux Ansible pour le supprimer de /dest/conf.d/.

Est-il possible de faire cela? J'ai essayé de bidouiller avec rsync --delete, mais là j'ai eu un problème avec les modèles qui obtiennent leur suffixe .j2 supprimé.

40
demandé sur Michael Krupp 2013-05-05 18:27:17

7 réponses

je le ferais comme ceci, en supposant qu'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
47
répondu user2645850 2018-06-13 09:36:25

nous faisons cela avec nos fichiers nginx, puisque nous voulons qu'ils soient dans un ordre spécial, viennent de gabarits, mais supprimons ceux qui ne sont pas 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

Le truc (comme vous pouvez le voir) est que template et with_items ont des attributs différents dans les résultats du registre. Puis vous tournez dans une liste de fichiers, de gérer et d'obtenir ensuite une liste de l'annuaire et supprimé ceux qui ne sont pas dans cette liste.

Peut ê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, donc j'ai besoin de créer la liste ainsi que la carte.

9
répondu dalore 2015-05-21 11:28:09

je veux partager mon expérience avec ce cas.

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

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

suivant nous pouvons vouloir supprimer les fichiers inutilisés de la directive config. C'est simple. Nous rassemblons la liste des fichiers téléchargés et des fichiers existent sur le serveur distant, puis supprimons diffrence.

mais nous pouvons vouloir avoir des fichiers non gérés dans config dir. J'ai utilisé -prune fonctionnalités find pour éviter de vider les dossiers avec des fichiers non gérés.

PS _(A)_ sûr après j'ai 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
répondu dmOx 2017-07-11 11:00:01

il pourrait y avoir plusieurs 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 templated dans un répertoire temporaire et ensuite Supprimer+Renommer dans une étape ultérieure?

2
répondu Tybstar 2013-05-05 22:41:15

voici quelque chose que j'ai trouvé:

- 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 }}"
  • génère les templates (de quelle manière vous voulez), et enregistre les résultats dans'template_results'
  • Les résultats sont déformés pour obtenir une simple liste de "dest" de chaque modèle. Les modèles sautés (en raison d'une condition quand, Non montré) n'ont pas d'attribut "invocation", donc ils sont filtrés.
  • "rechercher" est ensuite utilisé pour obtenir une liste de tous les fichiers qui doivent être absent, à moins que spécifiquement écrire.
  • ceci est ensuite modifié pour obtenir une liste brute des fichiers présents, puis les fichiers "supposés être là" sont supprimés.
  • le "files_to_delete" restant est alors supprimé.

Pros: vous évitez les entrées multiples "sautées" qui apparaissent pendant les suppressions.

contre: vous aurez besoin de concaténer chaque template_results.résultats si vous voulez faire plusieurs modèle de tâches avant de faire la recherche/supprimer.

2
répondu Chris Cogdon 2017-08-11 20:07:13

habituellement Je ne supprime pas les fichiers mais j'ajoute -unmanaged suffixe à son nom. Exemple ansible tâches:

- 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 faire de la recherche récursive
  • --include=\*.list - ne prendre que des fichiers avec. extension de liste lors de la recherche récursive
  • -L '^# Ansible' - afficher les noms de fichiers qui n'ont pas de ligne commençant par '# Ansible'
  • || true - ce est utilisé pour ignorer erreur. Ansible ignore_errors fonctionne aussi mais avant d'en ignorant l'erreur ansible montrera en couleur rouge pendant ansible-playbook exécuter ce qui est indésirable (au moins pour moi).

puis j'enregistre la sortie de la commande grep comme une variable. Lorsque grep affiche une sortie, j'ai modifié cette tâche (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 sautée.

1
répondu ahes 2014-05-24 07:04:49

apparemment ce n'est pas possible avec ansible pour le moment. J'ai eu une conversation avec mdehaan sur IRC et ça se résume à un possible qui n'a pas de courbe acyclique dirigée pour les ressources, ce qui rend les choses très difficiles.

demander à mdehaan un exemple par exemple gérer de manière autoritaire un sudoers.d: répertoire, il est venu avec 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
répondu Michael Renner 2013-08-02 12:43:23