Подтвердить что ты не робот

Ansible - удалить неуправляемые файлы из каталога?

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

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

4b9b3361

Ответ 1

Я сделал бы это так, предполагая, что переменная, определенная как "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

Ответ 2

Мы делаем это с нашими файлами 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 имеют разные атрибуты в результатах регистра. Затем вы превращаете их в список файлов, которыми вы управляете, а затем получаете список каталога и удаляете те, которые не входят в этот список.

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

Ответ 3

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

Необязательный из 2.2 имеет loop_filetree loop, который обеспечивает простой способ загрузки 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

Ответ 4

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

Ответ 5

Обычно я не удаляю файлы, но добавляю суффикс -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 ignore_errors также работает, но прежде, чем игнорировать ошибку, она будет отображаться красным цветом во время запуска загружаемого файла что нежелательно (по крайней мере для меня).

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

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

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

Ответ 6

Здесь что-то я придумал:

- 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" затем удаляются.

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

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

Ответ 7

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

Запрос 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