ansible - 从目录中删除非托管文件?

Mic*_*upp 43 ansible ansible-template

我想以递归方式复制目录并将所有.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"
Run Code Online (Sandbox Code Playgroud)

现在我正在寻找一种从该目录中删除非托管文件的方法.例如,如果我从/src/conf.d/我想要Ansible删除文件/模板也将其删除/dest/conf.d/.

有办法做到这一点吗?我试着摆弄rsync --delete,但在那里我遇到了模板的问题,它们的后缀.j2被删除了.

小智 50

我这样做,假设一个定义为'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
Run Code Online (Sandbox Code Playgroud)

  • 它确实有效.从我的头发中拯救了我. (2认同)

dal*_*ore 11

我们使用我们的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
Run Code Online (Sandbox Code Playgroud)

技巧(如您所见)是模板和with_items在寄存器结果中具有不同的属性.然后将它们转换为您管理的文件列表,然后获取目录列表并删除不在该列表中的目录.

如果您已经有一个文件列表,可以用更少的代码完成.但在这种情况下,我正在创建一个索引列表,因此需要使用map创建列表.

  • 这非常酷 - upvoted.我挣扎着它:如果你没有指定通配符,它​​会将完整路径和文件名与文件名进行比较,以便删除所有内容.而不是`ls -l`在这种情况下尝试`find {{nginx_conf_dir}} -type f` (2认同)

小智 5

我想与这个案例分享我的经验.

Ansible from 2.2 with with_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"
Run Code Online (Sandbox Code Playgroud)

接下来,我们可能希望从config dir中删除未使用的文件.这很简单.我们收集远程服务器上存在的上传文件和文件列表,然后删除差异.

但是我们可能希望在config dir中有非托管文件.我已经使用了避免使用非托管文件清除文件夹的-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
Run Code Online (Sandbox Code Playgroud)


小智 2

可能有多种方法可以处理此问题,但是是否可以在模板步骤之前完全清空任务中的目标目录?或者也许将模板文件放入临时目录中,然后在后续步骤中删除+重命名?

  • 在复制之前完全清空目标目录意味着播放总是会“改变”。即使没有对源目录进行任何更改。当本地重命名文件时(例如 rsync->render->rename->rsync),总是存在这样的问题:ansible 会在实际上没有更改时报告更改(重命名)。 (4认同)