Ansible:如何根据环境变量指定的选择器引入任务文件
问题:根据选择器动态引入Ansible任务文件
我有一个包含多个命名任务文件的文件夹,希望根据特定选择器引入这些文件。示例目录结构如下:
inventory_dir | stacks | tasks | app1.yml | app2.yml | app3.yml
选择器可以是一个列表,其中可能包含不存在对应任务文件的元素。我尝试了两种方法但均存在问题:
第一种方法:直接循环选择器
- name: tentative 1 block: - name: Tasks to execute always include_tasks: ./generic-tasks.yml - name: Include specific tasks for specific selector include_tasks: file: "{{ inventory_dir }}/stacks/tasks/{{ item }}.yml" loop: - '{{ SELECTOR }}'
此方法无法用stat任务提前检查文件是否存在(无法在block上循环),当选择器对应任务文件不存在时会执行失败。
第二种方法:遍历文件夹并过滤
- name: Include specific tasks for specific selector include_tasks: file: "{{ item }}" loop: "{{ lookup('fileglob', '{{ inventory_dir }}/stacks/tasks/*.yml',wantlist=True) }}" when: "item|regex_replace('(?:\/[ \w]+){1,}\/([ \w]+)(?:\.yml)', '\1') in SELECTOR"
该方法执行失败,推测是in检查逻辑出现问题(正则表达式本身可正常工作)。请问是否有更优的实现方案?
最优实现方案
推荐结合stat模块和循环选择器的方式,既可以提前校验文件存在性,又能灵活处理选择器中的无效项:
步骤1:预检查选择器对应的任务文件是否存在
先遍历选择器列表,用stat获取每个文件的存在状态,将结果保存为变量:
- name: Check if task files exist for selector items stat: path: "{{ inventory_dir }}/stacks/tasks/{{ item }}.yml" loop: "{{ SELECTOR }}" register: task_files_check
步骤2:筛选出存在的任务文件并引入
基于上一步的检查结果,过滤出存在的文件路径,再循环引入:
- name: Include generic tasks always include_tasks: ./generic-tasks.yml - name: Include existing specific tasks include_tasks: "{{ item.stat.path }}" loop: "{{ task_files_check.results | selectattr('stat.exists', 'equalto', true) | list }}" loop_control: label: "{{ item.item }}" # 循环显示选择器项,方便日志查看
可选:添加不存在文件的提示
如果需要对选择器中的无效项做日志提示,可以增加一个任务:
- name: Warn about missing task files debug: msg: "Task file for '{{ item.item }}' does not exist, skipping" loop: "{{ task_files_check.results | selectattr('stat.exists', 'equalto', false) | list }}" when: task_files_check.results | selectattr('stat.exists', 'equalto', false) | list | length > 0
方案优势
- 完全兼容选择器中的无效项,不会因为文件不存在导致playbook失败
- 逻辑清晰,分步骤处理检查和引入,便于维护和调试
- 可选的提示任务能让运维人员快速定位无效选择器项
另外,针对你第二种方法的问题,本质是lookup中嵌套变量的写法错误,正确写法应该直接拼接变量,不需要嵌套双引号:
loop: "{{ lookup('fileglob', inventory_dir ~ '/stacks/tasks/*.yml', wantlist=True) }}"
但即使修正后,该方法也无法主动提示选择器中的无效项,所以还是推荐分步检查的方案。
内容的提问来源于stack exchange,提问作者Aleritty
相关产品推荐
相关产品推荐

