我想以递归方式复制目录和将所有 .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
已被移除。
答案 0 :(得分:48)
我这样做,假设一个定义为'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
答案 1 :(得分: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
技巧(如您所见)是模板和with_items在寄存器结果中具有不同的属性。然后将它们转换为您管理的文件列表,然后获取目录列表并删除不在该列表中的目录。
如果您已经有一个文件列表,可以用更少的代码完成。但在这种情况下,我创建了一个索引列表,因此需要使用map创建列表。
答案 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"
接下来,我们可能希望从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
答案 3 :(得分:2)
可能有几种方法可以解决这个问题,但是可以在模板步骤之前完全清空任务中的目标目录吗?或者可以将模板文件放入临时目录,然后在后续步骤中删除+重命名?
答案 4 :(得分:1)
通常我不删除文件,但我在其名称后面添加-unmanaged
后缀。
示例ansible任务:
- 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
也有效,但在忽略错误之前,ansible将在ansible-playbook运行期间以红色显示
这是不受欢迎的(至少对我而言)。然后我将grep命令的输出注册为变量。当grep显示任何输出时,我将此任务设置为已更改(行changed_when
负责此操作)。
在下一个任务中,我迭代grep输出(即grep返回的文件名)并运行rename命令为每个文件添加后缀。
这就是全部。下次运行命令时,第一个任务应为绿色,第二个任务应跳过。
答案 5 :(得分:0)
显然,目前无法使用ansible。我在IRC上与mdehaan进行了一次对话,归结为没有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
答案 6 :(得分:0)
我使用的是 Ansible 版本 2.9.20
---
# tasks file for delete_unmanaged_files
- name: list files in dest
shell: ls -1 dest/conf.d
register: files_in_dest
- name: list files in src
shell: ls -1 src/conf.d
register: files_in_src
- name: Managed files - dest
command: echo {{ item|replace('.j2','') }}
with_items: "{{ files_in_dest.stdout_lines }}"
register: managed_files_dest
- name: Managed files - src
command: echo {{ item|replace('.j2','') }}
with_items: "{{ files_in_src.stdout_lines }}"
register: managed_files_src
- name: Convert src managed files to list
set_fact: managed_files_src_list="{{ managed_files_src.results | map(attribute='stdout') | list }}"
- name: Delete unmanaged files in dest
file: path=dest/conf.d/{{ item.stdout }} state=absent
with_items: "{{ managed_files_dest.results }}"
when: item.stdout not in managed_files_src_list
我认为根据此问题的用例,我发现上述解决方案可能对您有所帮助。在这里,我创建了 6 个任务。
说明: