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é.
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
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.
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
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?
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.
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. Ansibleignore_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.
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