Ansible lineinfile模块无法完整写入所有输出问题排查
问题描述
我写了一个Ansible Playbook,要执行命令sudo /usr/sbin/dmidecode -t1 | grep -i vmware | grep -i product,然后用lineinfile模块把结果写入本地文件/home/myuser/ansible/mine/vmware.out。批量多主机执行时,debug模块显示每个主机的结果都正确,但目标文件里只包含部分主机的记录;必须重复执行两次Playbook,文件才能完整写入所有记录。调整多次都没解决,-v/-vv日志也没异常。
附sudo dmidecode -t1命令输出:
# dmidecode 3.2 Getting SMBIOS data from sysfs. SMBIOS 2.4 present. Handle 0x0001, DMI type 1, 27 bytes System Information Manufacturer: VMware, Inc. Product Name: VMware Virtual Platform Version: None Serial Number: VMware-42 15 27 29 d2 1d 0b 1e-ec 62 1a 6b a1 f2 af 11 UUID: 12165229-d21d-0b0e-ec63-1b6aa2e7nf92 Wake-up Type: Power Switch SKU Number: Not Specified Family: Not Specified
问题根源
lineinfile模块默认是并行执行的,当多个主机同时往本地同一个文件写入时,会触发文件写入竞争——多个进程同时打开、修改文件,后执行的进程会覆盖或打断前一个进程的写入操作,导致部分记录丢失。第二次执行时,那些第一次没写入成功的主机重新执行写入,才会补全记录。
解决方案
方案1:改用fetch+assemble模块(推荐)
先把每个主机的结果收集到控制节点的临时目录,再合并成一个文件,彻底规避写入竞争:
- name: 收集VMware产品信息 hosts: all tasks: - name: 执行dmidecode命令获取产品信息 command: sudo /usr/sbin/dmidecode -t1 | grep -i vmware | grep -i product register: vmware_product - name: 将结果写入主机临时文件 copy: content: "{{ vmware_product.stdout }} ({{ inventory_hostname }})" dest: /tmp/vmware_{{ inventory_hostname }}.out - name: 拉取临时文件到控制节点 fetch: src: /tmp/vmware_{{ inventory_hostname }}.out dest: /tmp/vmware_results/ flat: yes - name: 合并所有主机记录到目标文件 hosts: localhost tasks: - name: 合并文件 assemble: src: /tmp/vmware_results/ dest: /home/myuser/ansible/mine/vmware.out regexp: '^vmware_.*\.out$' - name: 清理临时文件 file: path: /tmp/vmware_results/ state: absent
方案2:给lineinfile添加串行执行控制
通过run_once: true配合遍历所有主机的结果,让写入操作在控制节点串行执行,避免竞争:
- name: 收集并写入VMware产品信息 hosts: all tasks: - name: 执行dmidecode命令获取产品信息 command: sudo /usr/sbin/dmidecode -t1 | grep -i vmware | grep -i product register: vmware_product - name: 将所有结果写入本地文件 hosts: localhost tasks: - name: 串行写入每条记录 lineinfile: path: /home/myuser/ansible/mine/vmware.out line: "{{ item.stdout }} ({{ item.inventory_hostname }})" create: yes with_items: "{{ hostvars | dict2items | map(attribute='value.vmware_product') }}"
方案3:使用copy模块一次性写入所有结果
先收集所有主机的结果到一个变量,再一次性写入文件,同样避免并行写入:
- name: 收集VMware产品信息 hosts: all tasks: - name: 执行dmidecode命令获取产品信息 command: sudo /usr/sbin/dmidecode -t1 | grep -i vmware | grep -i product register: vmware_product - name: 批量写入所有记录 hosts: localhost tasks: - name: 生成所有记录内容 set_fact: all_vmware_records: | {% for host in groups['all'] %} {{ hostvars[host].vmware_product.stdout }} ({{ host }}) {% endfor %} - name: 写入目标文件 copy: content: "{{ all_vmware_records }}" dest: /home/myuser/ansible/mine/vmware.out force: yes
内容的提问来源于stack exchange,提问作者Cat Hariss
相关产品推荐
相关产品推荐

