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é.
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
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.
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
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}}"
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.
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?
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.
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