ansible – 从目录中删除非托pipe文件?

我想recursion复制一个目录并将其中的所有.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" 

现在我正在寻找一种从这个目录中删除非托pipe文件的方法。 例如,如果我从/src/conf.d/删除文件/模板,我希望Ansible将其从/dest/conf.d/删除。

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

我会这样做,假设一个variables定义为'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 

我们用我们的nginx文件来做这件事,因为我们希望它们是特殊的顺序,来自模板,但删除非托pipe的工作:

  # 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在注册结果中有不同的属性。 然后,将它们转换为您pipe理的文件列表,然后获取该目录的列表,并删除不在列表中的列表。

如果你已经有一个文件列表,可以用更less的代码来完成。 但在这种情况下,我创build一个索引列表,所以需要创build列表以及地图。

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

我想分享一下我的经验。

2.2的Ansible有with_filetree循环提供了简单的方法来上传dirs,链接,静态文件,甚至(!)模板。 这是保持我的configuration目录同步的最好方法。

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

接下来我们可能需要从configuration目录中删除未使用的文件。 这很简单。 我们收集远程服务器上存在的上传文件和文件列表,然后删除差异。

但是我们可能希望在configuration目录中有非托pipe文件。 我已经使用findfunction来避免使用非托pipe文件清除文件夹。

PS _(Y)_确定后,我删除了一些非托pipe文件

 - 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 

通常我不会删除文件,但我添加了-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做recursionsearch
  • --include=\*.list 。list – 在recursionsearch过程中只采用扩展名为.list的文件
  • -L '^# Ansible' – 显示没有以'#Ansible'开头的行的文件名
  • || true || true – 这是用来忽略错误。 Ansible的ignore_errors也起作用,但在忽略错误之前,ansible-playbook运行期间会显示为红色,这是不受欢迎的(至less对我而言)。

然后我把grep命令的输出注册为一个variables。 当grep显示任何输出时,我将此任务设置为已更改( changed_when行负责)。

在下一个任务中,我迭代grep输出(即由grep返回的文件名),并运行rename命令为每个文件添加后缀。

就这样。 下一次你运行命令第一个任务应该是绿色的,第二个跳过。

这是我想出的东西:

 -  template:src = / source / directory {{item}}。j2 dest = / target / directory / {{item}}
  注册: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}}”

 - debugging:
     var:managed_files
    详细程度:0

 - 找:
    path:“/ target / directory /”
    模式:“* .txt”
  注册:all_files
 -  set_fact:
     files_to_delete:“{{all_files.files | map(attribute ='path')| difference(managed_files)}}”

 - debugging:
     var:all_files
    详细程度:0
 - debugging:
     var:files_to_delete
    详细程度:0

 -  file:path = {{item}} state = absent
   with_items:“{{files_to_delete}}”
  • 这将生成模板(不pipe您想要的方式),并将结果logging在“template_results”
  • 结果被打乱以获得每个模板的“dest”的简单列表。 被跳过的模板(由于when条件,没有显示)没有“调用”属性,所以它们被过滤掉。
  • 然后使用“查找”来获得所有应该不存在的文件的列表,除非特别写入。
  • 这是后来mangle获取文件的原始列表,然后“应该在那里”文件被删除。
  • 其余的“files_to_delete”然后被删除。

优点:避免在删除过程中出现多个“跳过”的条目。

缺点:如果要在执行查找/删除操作之前执行多个模板任务,则需要连接每个template_results.results。

显然,目前这是不可能的。 我和IRC上的mdehaan进行了一次交谈,归结为没有一个有针对性的资源非循环图 ,这样做非常困难。

以mdehaan为例,例如权威地pipe理一个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