Ansible调用include_role引入file-cleaner角色未运行如何排查
运行环境
当前使用Ansible版本为2.10.8,版本查询结果如下:
$ ansible --version ansible 2.10.8
问题描述
编写名为file-cleaner的通用角色,用于删除文件名在指定列表内的文件,角色配置如下:
defaults/main.yml
remote_dir: "C:\\temp" files_to_delete: []
tasks/main.yml
- name: "Delete {{ files_to_delete }}" win_shell: del {{ item }} args: executable: cmd chdir: "{{ remote_dir }}" loop: "{{ files_to_delete }}"
在另一个角色中调用上述file-cleaner角色清理旧zip文件,调用逻辑如下:
- name: Get name of old files win_shell: dir /b *.zip args: executable: cmd chdir: "{{ remote_dir }}" register: old_files - debug: msg="{{ old_files.stdout_lines }}" - name: Delete old files include_role: name: file-cleaner vars: files_to_delete: "{{ old_files.stdout_lines }}"
运行playbook时,控制台输出到Delete old files任务后就无后续输出,被include_role引入的file-cleaner角色未实际运行:
TASK [role1 : Get name of old files] *************************************** changed: [10.x.x.x] TASK [role1 : debug] ******************************************************* ok: [10.x.x.x] => { "msg": [ "file1.zip", "file2.zip" ] } TASK [Delete old files] ****************************************************
问题原因
该问题是Ansible 2.10版本动态包含角色的渲染逻辑与角色任务写法冲突导致的:
include_role属于动态包含操作,角色内的任务不会在playbook启动阶段预解析,只有执行到include_role节点时才会开始加载任务、渲染变量。- 角色内首个任务的名称直接引用了完整的
files_to_delete列表变量,同时该任务本身对files_to_delete做loop迭代。Ansible加载任务时会先渲染任务名,需要获取files_to_delete的完整值;但files_to_delete是通过include_role动态传入的列表,loop迭代器的初始化又需要等待任务加载完成,两者形成循环等待,最终导致任务卡住无输出。 - 现有删除逻辑还有额外隐患:直接拼接
del {{ item }}执行shell命令,没有对文件名加引号包裹,一旦文件名包含空格、特殊字符就会执行失败。
解决方法
- 先修改
file-cleaner角色的tasks/main.yml,将任务名中对全量列表的引用改为当前迭代的文件项,同时给文件名加引号适配特殊字符,这一步就能解决卡住的问题:
- name: "Delete {{ item }}" win_shell: del "{{ item }}" args: executable: cmd chdir: "{{ remote_dir }}" loop: "{{ files_to_delete }}"
- (推荐优化)不需要依赖cmd命令执行删除,改用Ansible原生的
win_file模块实现文件删除,完全避免shell转义、执行路径的问题,稳定性更高:
- name: "Delete {{ item }}" win_file: path: "{{ remote_dir }}\\{{ item }}" state: absent loop: "{{ files_to_delete }}"
- (可选)如果不需要动态包含的特性(比如不需要根据运行时变量判断是否加载角色),可以将调用处的
include_role替换为静态导入的import_role,静态导入会在playbook启动预解析阶段就加载所有角色任务,从根源上避免动态渲染的循环等待问题:
- name: Delete old files import_role: name: file-cleaner vars: files_to_delete: "{{ old_files.stdout_lines }}"
内容的提问来源于stack exchange,提问作者Chris F
相关产品推荐
相关产品推荐

