ansible-是否从目录中删除非托管文件?
我想递归地复制目录并将其中的所有.j2文件作为模板呈现。为此,我目前使用以下行:ansible-是否从目录中删除非托管文件?,ansible,ansible-template,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" 现在我正在寻找一种从这个目录中删除非托管文件的方法。例如,如果我从/src/
- 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
被删除了。可能有两种方法来处理这个问题,但是在模板步骤之前是否可以在任务中完全清空目标目录?或者将模板文件放到临时目录中,然后在后续步骤中删除并重命名?我会这样做,假设顶部有一个定义为“managed_files”的变量,即列表
-shell:ls-1/some/dir
注册:目录
-文件:path=/some/dir/{{item}}state=不存在
带\u项:contents.stdout\u行
何时:项目不在托管_文件中
显然,目前ansible不可能做到这一点。我和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
14:17长袍:http://pastebin.com/yrdCZB0y
14:19mdehaan:HM
14:19mdehaan:这看起来相对正常
14:19谢谢:)
14:19我看到的问题是,我必须自己收集托管文件
14:19你会同意的
14:19几乎
14:20你可以做一个fileglob然后。。。那会有点恶心
[..]
14:32eh,理论语法,nm
14:33我可以通过编写一个过滤列表的查找插件来实现
14:34http://pastebin.com/rjF7QR24
14:34例如,如果该插件存在,并且在A中的列表中迭代,也在B中迭代
通常我不会删除文件,但会在其名称中添加-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
-仅获取文件 在递归搜索期间使用.list扩展名--include=\*.list
-显示没有以'#Ansible'开头的行的文件名-L'^#Ansible'
-用于忽略错误。Ansible的| | true
也可以工作,但在忽略错误之前,Ansible将在Ansible playbook运行期间以红色显示它 这是不想要的(至少对我来说)ignore_errors
changed\u行)
在下一个任务中,我迭代grep输出(即grep返回的文件名),并运行rename命令为每个文件添加后缀
就这些。下次运行命令时,第一个任务应为绿色,第二个任务将被跳过。我们使用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_项在寄存器结果中具有不同的属性。然后将它们转换为您管理的文件列表,然后获得目录列表,并删除不在该列表中的文件
如果您已经有一个文件列表,那么可以用更少的代码来完成。但在本例中,我正在创建一个索引列表,因此需要使用map创建该列表。我想与大家分享我在本例中的经验
Ansible from 2.2 is had with_filetree loop提供了上传目录、链接、静态文件甚至(!)模板的简单方法。这是保持配置目录同步的最佳方法
- 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 dir中删除未使用的文件。很简单。
我们收集上传文件和远程服务器上存在的文件的列表,然后删除差异
但我们可能希望在config dir中有非托管文件。
我使用了find
的-prune
功能来避免清除包含非托管文件的文件夹
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
以下是我想到的:
- 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 }}"
-模板:src=/source/directory{{item}}.j2 dest=/target/directory/{{item}
注册:模板\u结果
有以下项目:
-a_list.txt
-of_all.txt
-templates.txt
-设定事实:
托管_文件:“{template_results.results}selectattr('invocation','defined')| map(attribute='invocation.module_args.dest')| list}”
-调试:
var:managed_文件
详细程度:0
-查找:
路径:“/target/directory/”
模式:“*.txt”
注册:所有文件
-设定事实:
files_to_delete:“{{all_files.files | map(attribute='path')| difference(managed_files)}”
-调试:
var:所有文件
详细程度:0
-调试:
变量:要删除的文件
详细程度:0
-文件:路径={item}}}状态=不存在
与_项一起:“{{files_to_delete}”
- 这将生成模板(无论您希望以何种方式),并将结果记录在“模板结果”中
- 结果被破坏,得到每个模板的“dest”的简单列表。跳过的模板(由于when条件,未显示)没有“invocation”属性,因此会被过滤掉
- 然后使用“find”来获取除非特别编写,否则应该不存在的所有文件的列表
- 然后,这将被破坏,以获得当前文件的原始列表,然后删除“应该在那里”的文件
- 然后删除剩余的“要删除的文件”
优点:可以避免在删除过程中出现多个“跳过”条目
缺点:如果要执行mult,则需要将每个模板连接到results.results