Ansible动态添加ansible_hostname至YAML清单的问题排查
问题描述
原始Ansible YAML清单:
rpi_wifi: children: _wifi: hosts: 10.74.47.49 : 10.74.47.218: 10.74.47.70 :
目标是编写Playbook,从每个主机收集ansible_hostname变量,并添加到清单对应主机的下一行,编写的Playbook如下:
- name: Add ansible_hostname to hosts hosts: rpi_wifi gather_facts: true tasks: - name: Update inventory file with ansible_hostname_var lineinfile: path: hosts0.yml regexp: "{{ inventory_hostname }}" line: "{{ ansible_hostname }} \n {{ ansible_hostname }}" delegate_to: localhost
期望最终清单结构:
rpi_wifi: children: _wifi: hosts: 10.74.47.49 : ansible_hostname: foo 10.74.47.218: ansible_hostname: bar 10.74.47.70 : ansible_hostname: foo-bar
遇到两个问题:
- 随机遗漏部分主机的hostname添加,已通过
-vvv确认变量收集正常 - YAML缩进处理不灵活,无法适配清单中不同层级的空格缩进
解决方案
问题1:解决主机信息遗漏
原因
多个主机并行执行lineinfile修改同一文件时,会出现文件读写冲突,导致部分修改被覆盖或遗漏。
解决方法
方法1:串行执行任务
在Play中添加serial: 1,确保同一时间只有一个主机执行修改操作,避免并发冲突:
- name: Add ansible_hostname to hosts hosts: rpi_wifi gather_facts: true serial: 1 # 串行执行,一次处理一个主机 tasks: - name: Update inventory file with ansible_hostname_var lineinfile: path: hosts0.yml regexp: "^(\\s+){{ inventory_hostname }}\\s*:" line: "\\1{{ inventory_hostname }} :\n\\1 ansible_hostname: {{ ansible_hostname }}" backrefs: true delegate_to: localhost
方法2:模板批量生成(更可靠)
先批量收集所有主机的hostname信息,再通过Jinja2模板一次性生成完整清单,彻底避免并发问题:
- 创建模板文件
inventory.j2:
rpi_wifi: children: _wifi: hosts: {% for host in groups['rpi_wifi'] %} {{ host }} : ansible_hostname: {{ hostvars[host]['ansible_hostname'] }} {% endfor %}
- 编写Playbook:
- name: Collect all hostnames hosts: rpi_wifi gather_facts: true tasks: - name: Sync host info to localhost set_fact: host_info: "{{ host_info | default({}) | combine({ inventory_hostname: ansible_hostname }) }}" delegate_to: localhost - name: Generate updated inventory hosts: localhost tasks: - name: Write new inventory file template: src: inventory.j2 dest: hosts0.yml
问题2:解决YAML缩进问题
方法1:正则捕获原行缩进
如果坚持使用lineinfile,可以通过正则捕获主机行的前导空格,再用该空格+2个缩进实现层级对齐:
- name: Update inventory file with ansible_hostname_var lineinfile: path: hosts0.yml regexp: "^(\\s+){{ inventory_hostname }}\\s*:" line: "\\1{{ inventory_hostname }} :\n\\1 ansible_hostname: {{ ansible_hostname }}" backrefs: true # 启用正则分组引用 delegate_to: localhost
其中\\1代表捕获到的原行前导空格,后续添加的ansible_hostname行会自动继承原缩进并增加2个空格,符合YAML层级要求。
方法2:模板自动处理缩进
前面提到的模板生成方式会直接按照YAML结构生成内容,无需手动计算空格,天然保证缩进正确,是最稳妥的方案。
内容的提问来源于stack exchange,提问作者Disbalance
相关产品推荐
相关产品推荐

