2013-05-05 16 views
38

Я хочу, чтобы рекурсивно скопировать к каталогу и показать все .j2 файлы там, как шаблоны. Для этого я в настоящее время использую следующие строки:ansible - удалить неуправляемые файлы из каталога?

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

Сейчас я ищу способ, чтобы удалить неуправляемые файлы из этого каталога. Например, если я удаляю файл/шаблон из /src/conf.d/, я хочу, чтобы Ansible удалял его с /dest/conf.d/.

Есть ли способ сделать это? Я пробовал работать с rsync --delete, но там у меня возникла проблема с шаблонами, которые получили их суффикс .j2.

ответ

2

Возможно, существует несколько способов справиться с этим, но возможно ли полностью очистить целевой каталог в задаче до шага шаблона? Или, возможно, поместите шаблонные файлы во временный каталог, а затем удалите + переименовать на следующем шаге?

+2

Полная очистка каталога цели до копирования означает, что игра всегда будет «изменяться». Даже если в исходный каталог не было изменений. При локальном переименовании файлов (например, rsync-> render-> rename-> rsync) всегда существует проблема, которая может сообщить об изменениях (переименование), когда на самом деле нет изменений. –

+1

@keks 'changed_when: false' исправит это – ffghfgh

+0

Но вы хотите знать, когда/если файл конфигурации был изменен для запуска обработчиков – dalore

45

Я бы сделал это так, считая переменную, определенную как «managed_files» вверху, которая является списком.

- 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

Спасибо. Прекрасно работает. Теперь, какие-либо советы о том, как я удаляю файлы, если мои управляемые файлы не имеют расширения файлов, но мои файлы? Возможно, это должен быть еще один вопрос. – Batandwa

+1

Это на самом деле работает. Спасала меня от завершения моих волос. – Bwire

+1

@Batandwa вы можете использовать фильтр jinja, например: 'when: item | regex_replace ('^ (. *) \\. Ext $', '\\ 1') не в managed_files' – menghan

0

По-видимому, в настоящее время это невозможно сделать с невозможным. У меня был разговор с mdehaan на IRC, и он сводится к тому, что у него нет ресурсов directed acyclic graph, что делает такие вещи очень сложными.

Запрашивать mdehaan для примера, например. авторитетно управляющего каталогом sudoers.d он придумал эти вещи:

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

Обычно я не удалять файлы, но я добавить -unmanaged суффикс к его имени. Примеры анзибль задачи:

- 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 

ОБЪЯСНЕНИЕ

Grep команда использует:

  • -r сделать рекурсивный поиск
  • --include=\*.list - принимать только файлы с .list расширением во время рекурсивного поиска
  • -L '^# Ansible' - отображать имена файлов, которые не имеют строки, начинающейся с «# Ansible»
  • || true - это используется для игнорирования ошибок. Ansible's ignore_errors также работает, но прежде чем игнорировать ошибку, она будет отображаться красным цветом во время прослушивания незанятой игры , что нежелательно (по крайней мере для меня).

Затем я регистрирую вывод команды grep как переменной. Когда grep отображает любой выход, я задаю эту задачу как измененную (за это отвечает строка changed_when).

В следующей задаче я повторяю вывод grep (т. Е. Имена файлов, возвращаемые grep) и запускаю команду rename для добавления суффикса в каждый файл.

Вот и все. В следующий раз, когда вы запустите команду, первая задача должна быть зеленой, а вторая пропущена.

+0

Спасибо! Это мой предпочтительный способ сделать это сейчас, потому что верхний проголосовавший комментарий не справляется с тем, что «материал не изменился» очень хорошо. –

8

Мы делаем это с нашими Nginx файлами, так как мы хотим, чтобы они были в особом порядке, исходят из шаблонов, но удалить неуправляемые то это работает:

# 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 

Хитрость (как вы можете видеть) является этот шаблон и with_items имеют разные атрибуты в результатах регистра. Затем вы превращаете их в список файлов, которыми вы управляете, а затем получаете список каталога и удаляете те, которые не входят в этот список.

Может быть сделано с меньшим количеством кода, если у вас уже есть список файлов. Но в этом случае я создаю индексированный список, поэтому вам нужно создать список вместе с картой.

+2

Это очень круто - выслушано. Я боролся с ним, хотя: если вы не укажете подстановочный знак, он будет сравнивать полный путь и имя файла только с именем файла, чтобы он удалял все. Вместо 'ls -l' try' find {{nginx_conf_dir}} -type f' вместо этого в этом сценарии – Erfan

5

Я хочу поделиться своим опытом с этим делом.

Ansible from 2.2 имеет loop_filetree обеспечивает простой способ загрузки dirs, ссылок, статических файлов и даже (!) Шаблонов. Это лучший способ сохранить синхронизацию моего конфигуратора.

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

Дальше мы можем удалить неиспользуемые файлы из каталога config. Это просто. Мы собираем список загруженных файлов и файлов на удаленном сервере, затем удаляем diffrence.

Но мы можем захотеть иметь неуправляемые файлы в каталоге config. Я использовал -prune функциональность find, чтобы избежать очистки папок с неуправляемыми файлами.

PS _ (Y) _ уверен после того, как я удалил некоторые неуправляемые файлы

- 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

Это очень умно и должно иметь больше голосов !!! –

1

Вот что я придумал:

 
- 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 }}" 
  • Это создает шаблоны (впрочем, какой путь вы хочу) и записывает результаты в 'template_results'
  • Результаты искалечены, чтобы получить простой список «dest» каждого шаблона. Пропущенные шаблоны (из-за того, что условие, не показано) не имеют атрибута «invocation», поэтому они отфильтровываются.
  • «find» затем используется для получения списка всех файлов, которые должны отсутствовать, если специально не указано.
  • это затем искалечено, чтобы получить необработанный список присутствующих файлов, а затем файлы «предполагается, что они есть» удалены.
  • Остальные «files_to_delete» затем удаляются.

Плюсы: вы избегаете появления нескольких «пропущенных» записей во время удаления.

Против: вам нужно будет объединить каждый шаблон_results.results, если вы хотите сделать несколько задач шаблона, прежде чем выполнять поиск/удаление.

 Смежные вопросы

  • Нет связанных вопросов^_^