2013-05-05 7 views
38

Chcę rekurencyjnie skopiować ponad katalog i renderować wszystkie pliki .j2 tam jako szablony. Do tego jestem obecnie stosując następujące linie:ansible - usuwanie niezarządzanych plików z katalogu?

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

teraz szukam sposobu, aby usunąć pliki niezarządzanymi z tego katalogu. Na przykład, jeśli usunę plik/szablon z /src/conf.d/, chcę też, aby Ansible usunął go również z /dest/conf.d/.

Czy jest jakiś sposób, aby to zrobić? Próbowałem bawić się przy pomocy rsync --delete, ale dostałem problem z szablonami, które usunęły ich przyrostek .j2.

Odpowiedz

2

Może być kilka sposobów na poradzenie sobie z tym, ale czy możliwe byłoby całkowite opróżnienie katalogu docelowego w zadaniu przed etapem szablonu? A może upuścić pliki szablonów do katalogu tymczasowego, a następnie usunąć + zmienić nazwę w kolejnym kroku?

+2

Całkowite opróżnienie katalogu docelowego przed kopiowaniem oznaczałoby, że odtwarzanie będzie zawsze "zmieniać się". Nawet jeśli nie wprowadzono żadnych zmian w katalogu źródłowym. Podczas lokalnej zmiany nazw plików (np. Rsync-> render-> rename-> rsync) zawsze jest problem, że ansibry zgłosi zmiany (zmianę nazwy), gdy naprawdę nie ma żadnych zmian. –

+1

@keks 'changed_when: false' naprawi to – ffghfgh

+0

Ale chcesz wiedzieć, kiedy/jeśli plik konfiguracyjny został zmieniony, aby uruchomić procedury obsługi – dalore

45

Zrobiłbym to w ten sposób, zakładając zmienną zdefiniowaną jako "managed_files" w górę, która jest listą.

- 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

Dzięki. Działa świetnie. Teraz jakieś porady dotyczące usuwania plików, jeśli moje managed_files nie mają rozszerzenia nazwy pliku, ale moje pliki robią? Być może to powinno być zupełnie inne pytanie. – Batandwa

+1

To faktycznie działa. Uratował mnie od wykańczania włosów. – Bwire

+1

@ Batatwa możesz użyć filtru jinja, tak: 'when: item | regex_replace ('^ (. *) \\. Ext $', '\\ 1') nie w managed_files' – menghan

0

Wygląda na to, że obecnie nie jest to możliwe. Miałem rozmowę z mdehaanem na IRC i sprowadza się to do ansibla, nie mając zasobów, co czyni takie rzeczy bardzo trudnymi.

Pytanie o mdehaan za przykład, np. autorytatywnie zarządzania katalogu sudoers.d wymyślił te rzeczy:

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

Zazwyczaj nie usunąć pliki, ale dodam -unmanaged przyrostek do jego nazwy. Przykładowe ansibl zadania:

- 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 

WYJAŚNIENIE

Grep komenda używa:

  • -r zrobić rekurencyjne przeszukiwanie
  • --include=\*.list - tylko brać pliki z .list rozszerzeniem podczas rekurencyjnego wyszukiwania
  • -L '^# Ansible' - wyświetla nazwy plików, które nie mają linii zaczynającej się od '# Ansible'
  • || true - służy do zignorowania błędów. Answer's ignore_errors również działa, ale przed zignorowaniem błędu ansibli pokaże go w kolorze czerwonym podczas ansibli-playbook run co jest niepożądane (przynajmniej dla mnie).

Następnie rejestruję wyjście polecenia grep jako zmienną. Kiedy grep wyświetla jakiekolwiek dane wyjściowe, ustawiam to zadanie jako zmienione (linia changed_when jest za to odpowiedzialna).

W następnym zadaniu wykonuję iterację grep (tzn. Nazwy plików zwracane przez grep) i uruchamiam polecenie zmiany nazwy, aby dodać sufiks do każdego pliku.

To wszystko. Przy następnym uruchomieniu polecenia pierwsze zadanie powinno być zielone, a drugie pominięte.

+0

Dzięki! To jest mój preferowany sposób robienia tego teraz, ponieważ najlepszy głosujący komentarz nie radzi sobie bardzo dobrze z "rzeczami niezmienionymi". –

8

Robimy to z naszych plików nginx, ponieważ chcemy, aby być w specjalnej kolejności, pochodzą z szablonów, ale usunąć te niezarządzanymi to działa:

# 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 

Sztuką (jak widać) jest ten szablon i with_items mają różne atrybuty w wynikach rejestru. Następnie zamieniasz je w listę plików, którymi zarządzasz, a następnie otrzymujesz listę katalogu i usuwasz te, które nie znajdują się na tej liście.

Można zrobić mniej kodu, jeśli masz już listę plików. Ale w tym przypadku tworzę indeksowaną listę, więc trzeba utworzyć listę wraz z mapą.

+2

To jest bardzo fajne - przegłosowano. Jednak walczyłem z tym: jeśli nie określisz symbolu wieloznacznego, porówna on pełną ścieżkę i nazwę pliku tylko do nazwy pliku, więc usunie wszystko. Zamiast 'ls -l' spróbuj' find {{nginx_conf_dir}} -type f' zamiast tego scenariusza – Erfan

5

Chcę podzielić się moim doświadczeniem w tej sprawie.

Odporność na błędy z 2.2 ma pętlę with_filetree zapewniającą prosty sposób przesyłania katalogów, linków, plików statycznych, a nawet (!) Szablonów. To najlepszy sposób na synchronizację mojego katalogu konfiguracyjnego.

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

Następnie możemy chcieć usunąć nieużywane pliki z katalogu konfiguracyjnego. To proste. Zbieramy listę przesłanych plików i plików istnieje na serwerze zdalnym, a następnie usuń diffrence.

Ale możemy chcieć mieć niezarządzane pliki w katalogu konfiguracyjnym. Użyłem funkcji -prune z find, aby uniknąć usuwania folderów z niezarządzanych plików.

PS _ (Y) _ na pewno po tym, jak zostały usunięte niektóre niezarządzanymi plików

- 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

To jest bardzo sprytne i powinno mieć więcej głosów !!! –

1

Oto coś wymyśliłem:

 
- 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 }}" 
  • ta generuje szablony (jednak, w jaki sposób ci chcesz) i zapisuje wyniki w 'template_results'
  • Wyniki są zniekształcane, aby uzyskać prostą listę "dest" każdego szablonu. Pominięte szablony (ze względu na warunek when, nie pokazane) nie mają atrybutu "invocation", więc są odfiltrowywane.
  • "Znajdź" jest następnie używane, aby uzyskać listę wszystkich plików, które powinny być nieobecne, chyba że zostały specjalnie napisane.
  • to jest następnie zniekształcone, aby uzyskać listę plików obecnych, a następnie pliki "przypuszczalnie tam" są usuwane.
  • Pozostałe "files_to_delete" są następnie usuwane.

Zalety: Unikniesz wielu "pomijanych" wpisów pojawiających się podczas usuwania.

Wady: Konieczne będzie połączenie poszczególnych wyników template_results.results, jeśli chcesz wykonać wiele zadań szablonu przed wykonaniem wyszukiwania/usunięcia.