2013-05-05 19 views
38

Ich möchte rekursiv über ein Verzeichnis kopieren und rendern alle .j2 Dateien dort als Vorlagen. Dafür ich bin derzeit mit den folgenden Zeilen:ansible - löschen nicht verwaltete Dateien aus dem Verzeichnis?

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

Jetzt nach einem Weg, ich bin auf der Suche nicht verwalteten Dateien aus diesem Verzeichnis zu entfernen. Zum Beispiel, wenn ich eine Datei/Vorlage von /src/conf.d/ entferne, möchte ich, dass es auch von /dest/conf.d/ entfernt werden kann.

Gibt es einen Weg, dies zu tun? Ich habe versucht, mit rsync --delete herumzutüfteln, aber dort bekam ich ein Problem mit den Vorlagen, die ihr Suffix .j2 entfernen lassen.

Antwort

2

Es gibt möglicherweise mehrere Möglichkeiten, dies zu umgehen, aber wäre es möglich, das Zielverzeichnis in einer Aufgabe vor dem Vorlagenschritt vollständig zu leeren? Oder können Sie die Vorlagen in ein temporäres Verzeichnis kopieren und dann in einem späteren Schritt löschen + umbenennen?

+2

Das vollständige Löschen des Zielverzeichnisses vor dem Kopieren würde bedeuten, dass sich das Spiel immer ändert. Auch wenn keine Änderungen am Quellverzeichnis vorgenommen wurden. Beim lokalen Umbenennen der Dateien (z. B. rsync-> render-> rename-> rsync) gibt es immer das Problem, dass ansible Änderungen (die Umbenennung) meldet, wenn wirklich keine Änderungen vorliegen. –

+1

@keks 'changed_when: false' wird das beheben – ffghfgh

+0

Aber Sie möchten wissen, wann/wenn eine Konfigurationsdatei geändert wurde, um Handler zu starten – dalore

45

Ich würde es so machen, unter der Annahme einer Variablen definiert als 'managed_files' oben, das ist eine 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 
+0

Danke. Funktioniert super. Nun, irgendwelche Ratschläge, wie ich Dateien entfernen würde, wenn meine managed_files keine Dateinamenerweiterungen haben, aber meine Dateien tun? Vielleicht sollte das eine andere Frage sein. – Batandwa

+1

Es funktioniert tatsächlich. Rettete mir einen von meinen Haaren zu beenden. – Bwire

+1

@Batandwa können Sie jinja Filter verwenden, wie folgt: 'when: item | regex_replace ('^ (. *) \\. Ext $', '\\ 1') nicht in managed_files' – menghan

0

Scheinbar ist dies mit ansible im Moment nicht möglich. Ich hatte ein Gespräch mit mdehaan im IRC und es läuft darauf hinaus, dass ich keine directed acyclic graph für Ressourcen habe, was solche Dinge sehr schwierig macht.

Fragen mdehaan für ein Beispiel, z.B. autoritativ ein sudoers.d Verzeichnis Verwaltung kam er mit diesen Dingen auf:

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 
1

Normalerweise kann ich keine Dateien entfernen, aber ich hinzufügen -unmanaged Suffix zu seinem Namen. Beispiel ansible Aufgaben:

- 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 

ERKLÄRUNG

Grep Befehl verwendet:

  • -r rekursive Suche
  • --include=\*.list zu tun - nur Dateien nehmen mit .list Erweiterung während rekursive Suche
  • -L '^# Ansible' - Zeigt Dateinamen an, die keine Zeile haben, beginnend mit '# Ansible'
  • || true - dies wird verwendet, um Fehler zu ignorieren. Ansible's ignore_errors funktioniert auch, aber vor dem Ignorieren des Fehlers ansible wird es in rot während Ansible-Playbook Lauf zeigen, die (zumindest für mich) unerwünscht ist.

Dann registriere ich Ausgabe von grep Befehl als eine Variable. Wenn grep eine Ausgabe anzeigt, ändere ich diese Aufgabe als geändert (die Zeile changed_when ist dafür verantwortlich).

In der nächsten Aufgabe Ipeate grep Ausgabe (d. H. Dateinamen von grep zurückgegeben) und run Rename-Befehl, um Suffix zu jeder Datei hinzuzufügen.

Das ist alles. Wenn Sie das nächste Mal den Befehl ausführen, sollte die erste Aufgabe grün und die zweite übersprungen sein.

+0

Danke! Dies ist meine bevorzugte Art, dies jetzt zu tun, weil der oben gewählte Kommentar nicht sehr gut mit "Sachen hat sich nicht verändert" umgegangen ist. –

8

Wir tun dies mit unseren nginx-Dateien, da wir sie sein in einer bestimmten Reihenfolge wollen, kommen aus Vorlagen, aber nicht verwalteten diejenigen entfernen dies funktioniert:

# 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 

Der Trick (wie man sieht) ist Diese Schablone und with_items haben unterschiedliche Attribute in den Registerergebnissen. Dann verwandeln Sie sie in eine Liste von Dateien, die Sie verwalten, und erhalten dann eine Liste des Verzeichnisses und entfernt diejenigen, die nicht in dieser Liste sind.

Könnte mit weniger Code gemacht werden, wenn Sie bereits eine Liste von Dateien haben. Aber in diesem Fall erstelle ich eine indizierte Liste, also muss ich die Liste auch mit Karte erstellen.

+2

Das ist sehr cool - upvoted. Ich habe jedoch damit gekämpft: Wenn Sie den Platzhalter nicht angeben, vergleicht er den vollständigen Pfad und den Dateinamen mit dem Dateinamen, damit alles gelöscht wird. Anstelle von "ls -l" versuche stattdessen "find {{nginx_conf_dir}} -type f" in diesem Szenario – Erfan

5

Ich möchte meine Erfahrungen mit diesem Fall teilen.

Ansible von 2.2 hat hatte mit_filetree loop bietet eine einfache Möglichkeit zum Hochladen von dirs, Links, statische Dateien und sogar (!) Vorlagen. Es ist der beste Weg, mein Konfigurationsverzeichnis synchron zu halten.

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

Als nächstes möchten wir möglicherweise nicht verwendete Dateien aus dem Config-Verzeichnis löschen. Es ist einfach. Wir sammeln eine Liste der hochgeladenen Dateien und Dateien existieren auf dem entfernten Server, entfernen Sie als nächstes diffrence.

Aber wir möchten möglicherweise nicht verwaltete Dateien in Config-Verzeichnis haben. Ich habe -prune Funktionalität von find verwendet, um das Löschen von Ordnern mit nicht verwalteten Dateien zu vermeiden.

PS _ (Y) _ sicher, nachdem ich einige nicht verwalteten Dateien gelöscht haben

- 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 
+0

Das ist sehr clever und sollte mehr Stimmen haben !!! –

1

Hier ist etwas, was ich kam mit:

 
- 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 }}" 
  • Diese Vorlagen erzeugt (aber welche Art und Weise Sie will), und zeichnet die Ergebnisse in 'template_results' auf
  • Die Ergebnisse sind verfälscht, um eine einfache Liste der "dest" jeder Vorlage zu erhalten. Übersprungene Vorlagen (aufgrund einer nicht dargestellten Bedingung "when") haben kein "Aufruf" -Attribut, so dass sie herausgefiltert werden.
  • "find" wird dann verwendet, um eine Liste aller Dateien zu erhalten, die fehlen sollten, sofern nicht speziell geschrieben.
  • Dies wird dann gemangled, um eine rohe Liste der vorhandenen Dateien zu erhalten, und dann werden die "angeblich da sein" -Dateien entfernt.
  • Die verbleibenden "files_to_delete" werden dann entfernt.

Pro: Sie vermeiden mehrere 'übersprungene' Einträge, die während Löschungen angezeigt werden.

Nachteile: Sie müssen jedes template_results.results verketten, wenn Sie vor dem Suchen/Löschen mehrere Vorlagenaufgaben ausführen möchten.

Verwandte Themen