Ansible使用循环生成变量创建目录树时的问题咨询
问题:Ansible批量生成目录树时变量引用出错
我计划通过定义目录树模式字典,结合指定索引列表让Ansible创建多套相似目录树,编写了如下Playbook:
- hosts: [localhost] vars: instances: [1,2,3,4] dirs: - path: "/srvs/hosting{{ instance }}/dir1" - path: "/srvs/hosting{{ instance }}/dir2" # and so on ...... tasks: - debug: msg: "{{ item[1].path }}" loop: "{{ instances | product(dirs) | list }}" vars: instance: "{{ item[0] }}"
执行后出现错误:
fatal: [localhost]: FAILED! => {"msg": "[{'path': '/srvs/hosting{{ instance }}/dir1'}, {'path': '/srvs/hosting{{ instance }}/dir2'}]: {{ item[0] }}: 'item' is undefined"}
我期望的输出是:
ok: [localhost] => (item=[1, {'path': '/srvs/hosting1/dir1'}]) => { "msg": { "path": "/srvs/hosting1/dir1" } } ok: [localhost] => (item=[1, {'path': '/srvs/hosting1/dir2'}]) => { "msg": { "path": "/srvs/hosting1/dir2" } } ok: [localhost] => (item=[2, {'path': '/srvs/hosting2/dir1'}]) => { "msg": { "path": "/srvs/hosting2/dir1" } } ok: [localhost] => (item=[2, {'path': '/srvs/hosting2/dir2'}]) => { "msg": { "path": "/srvs/hosting2/dir2" } } ok: [localhost] => (item=[3, {'path': '/srvs/hosting3/dir1'}]) => { "msg": { "path": "/srvs/hosting3/dir1" } } ok: [localhost] => (item=[3, {'path': '/srvs/hosting3/dir2'}]) => { "msg": { "path": "/srvs/hosting3/dir2" } } ok: [localhost] => (item=[4, {'path': '/srvs/hosting4/dir1'}]) => { "msg": { "path": "/srvs/hosting4/dir1" } } ok: [localhost] => (item=[4, {'path': '/srvs/hosting4/dir2'}]) => { "msg": { "path": "/srvs/hosting4/dir2" } }
问题原因
问题出在变量渲染时机不匹配:
Ansible在加载Play的vars段时,会立刻尝试解析所有变量中的模板语法。但你定义的instance变量是在task的loop块里才创建的(属于task级临时变量),在Play加载vars阶段根本不存在,所以解析{{ instance }}时会找不到item(instance依赖item[0],而此时item还没生成),最终报错。
修复方案
方案一:使用路径模板,在循环时动态渲染
把目录路径定义为不带变量的模板字符串,在循环时用format方法替换实例索引:
- hosts: [localhost] vars: instances: [1,2,3,4] dir_templates: - "/srvs/hosting{instance}/dir1" - "/srvs/hosting{instance}/dir2" tasks: - debug: msg: "{{ item[1].format(instance=item[0]) }}" loop: "{{ instances | product(dir_templates) | list }}"
方案二:拆分路径固定部分与可变部分,循环时拼接
把目录的固定前缀、可变索引、后缀拆分,在循环时直接拼接生成完整路径,逻辑更直观:
- hosts: [localhost] vars: instances: [1,2,3,4] dir_suffixes: - "dir1" - "dir2" tasks: - debug: msg: "/srvs/hosting{{ item[0] }}/{{ item[1] }}" loop: "{{ instances | product(dir_suffixes) | list }}"
如果要实际创建目录,把debug模块换成file模块即可:
- file: path: "/srvs/hosting{{ item[0] }}/{{ item[1] }}" state: directory loop: "{{ instances | product(dir_suffixes) | list }}"
内容的提问来源于stack exchange,提问作者Kirill Zelepukin
相关产品推荐
相关产品推荐

