You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多主机场景下Ansible自定义Filter Plugin写入JSON报错求助

问题描述

我是Python新手,正在开发一款Ansible自定义过滤器插件。单主机执行相关Playbook时插件运行正常,但多主机(host1和host2)执行时出现报错,错误提示为“Extra data: line 21 column 2 (char 273)”。查看生成的JSON文件,发现存在}{格式问题,导致JSON解析失败。

示例Playbook

hosts: host1:host2
  tasks:
    - name: 生成0-10的随机数
      command: shuf -i 0-10 -n 1
      register: out
      until: out | customfilter1(file, ansible_hostname) or out.stdout == "2"
      retries: 50
      delay: 0
      vars:
        file: ./file.json

自定义过滤器customfilter1代码

#!/usr/bin/python
import os
import json

class FilterModule(object):
    def filters(self):
        return {
            'customfilter1': self.customfilter1
        }

    def customfilter1(self, obj, file, ansible_hostname):
        if obj["attempts"] == 1:
            print(obj)
            newdata = {ansible_hostname: {"Attempts": {obj["attempts"]: {"Result": obj["stdout"]}}}}
            json_file = json.dumps(newdata, sort_keys=False, indent=2)
            with open(file, 'a') as f:
                f.write(json_file)
        else:
            with open(file) as f:
                data = json.load(f)
            data[ansible_hostname]["Attempts"][obj["attempts"]] = {"Result": obj["stdout"]}
            json_file = json.dumps(data, sort_keys=False, indent=2)
            with open(file, 'w') as f:
                f.write(json_file)

        return False

报错信息

fatal: [ampere]: FAILED! => {"msg": "The conditional check 'out | customfilter1(file, ansible_hostname) or out.stdout == \"2\"' failed. The error was: Extra data: line 21 column 2 (char 273)"}

生成的异常JSON内容

{
  "host1": {
    "Attempts": {
      "1": {
        "Result": "4"
      },
      "2": {
        "Result": "5"
      },
      "3": {
        "Result": "7"
      },
      "4": {
        "Result": "0"
      },
      "5": {
        "Result": "2"
      }
    }
  }
}{
  "host2": {
    "Attempts": {
      "1": {
        "Result": "5"
      }
    }
  }
}
解决方案

问题根源是多主机并行执行时,第一个主机写入完整JSON对象后,第二个主机首次执行(attempts=1)会用追加模式直接写入另一个JSON对象,导致文件变成两个独立JSON对象的拼接(}{),不符合JSON规范,后续解析失败。同时多进程并发读写文件也会加剧数据损坏的概率。

修复后的过滤器代码

#!/usr/bin/python
import os
import json
from filelock import FileLock

class FilterModule(object):
    def filters(self):
        return {
            'customfilter1': self.customfilter1
        }

    def customfilter1(self, obj, file, ansible_hostname):
        # 用文件锁保证同一时间只有一个进程操作JSON文件
        lock_file = f"{file}.lock"
        with FileLock(lock_file):
            # 处理文件不存在或为空的情况
            if not os.path.exists(file) or os.path.getsize(file) == 0:
                data = {}
            else:
                with open(file, 'r') as f:
                    try:
                        data = json.load(f)
                    except json.JSONDecodeError:
                        # 若文件已损坏,重置为空对象
                        data = {}

            # 初始化当前主机的Attempts结构
            if ansible_hostname not in data:
                data[ansible_hostname] = {"Attempts": {}}
            
            # 添加当前尝试的结果,注意将attempts转为字符串避免JSON键类型问题
            data[ansible_hostname]["Attempts"][str(obj["attempts"])] = {"Result": obj["stdout"]}

            # 写入文件
            with open(file, 'w') as f:
                json.dump(data, f, sort_keys=False, indent=2)

        return False

注意事项

  1. 需先安装filelock库:执行pip install filelock,确保Ansible运行环境能访问该库。
  2. 原异常JSON中"host1:的引号缺失是笔误,修复后的代码会自动生成格式合法的JSON。
  3. 文件锁机制避免了多主机并行读写时的冲突,保证JSON结构始终符合规范。

内容的提问来源于stack exchange,提问作者EdFred

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 00:05:11