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

Python生成动态Ansible Playbook时JSON数据无法正确填充问题

问题:动态生成Ansible Playbook时无法填充install字段属性

我通过Python脚本从MySQL获取数据,结合Jinja2模板生成动态Ansible Playbook。已确认能从数据库正确拉取JSON格式的install/uninstall数据,但生成的Playbook无法正确填充install字段中的name与package_name等值。

代码片段

query = "SELECT vm_id, install, uninstall FROM vm_released_applications"
cursor.execute(query)
data = cursor.fetchall()

cursor.close()
connection.close()

return data

def create_dynamic_playbook(template_file, output_file, context):
    env = Environment(loader=FileSystemLoader(searchpath="./"))
    template = env.get_template(template_file)
    playbook_content = template.render(context)
    
    with open(output_file, 'w') as file:
        file.write(playbook_content)

def main():
    data = fetch_data_from_mysql()
    
    for record in data:
        vm_id = record['vm_id']
        install = json.loads(record['install']) if record['install'] else []
        uninstall = json.loads(record['uninstall']) if record['uninstall'] else []

        # Print statements to verify the JSON parsing
        print(f"VM ID: {vm_id}")
        print(f"Install Data: {json.dumps(install, indent=4)}")
        print(f"Uninstall Data: {json.dumps(uninstall, indent=4)}")   
        
        context = {
            'vm_id': vm_id,
            'install': install,
            'uninstall': uninstall
        }

        playbook_filename = f'playbook_vm_{vm_id}.yml'
        create_dynamic_playbook('playbook_template.yml.j2', playbook_filename, context)
        print(f"Playbook {playbook_filename} created successfully.")

if __name__ == "__main__":
    main()

JSON解析输出

VM ID: 43
Install Data: [
    "{\"id\":4,\"name\":\"Google Chrome\",\"package_name\":\"googlechrome\",\"version\":\"\"}"
]
Uninstall Data: []
Playbook playbook_vm_43.yml created successfully.

数据库示例数据

id;vm_id;install;uninstall;created_at;updated_at
2;52;["{\"id\":4,\"name\":\"Google Chrome\",\"package_name\":\"googlechrome\",\"version\":\"\"}"];;2024-07-10 08:03:29;2024-07-10 08:03:29

Jinja2模板

---
- name: Playbook for VM {{ vm_id }}
  hosts: all
  become: true
  tasks:
{% for item in install %}
    - name: Install {{ item.name }}
      win_chocolatey:
        name: "{{ item.package_name }}"
        state: present
{% endfor %}
{% for item in uninstall %}
    - name: Uninstall {{ item.name }}
      win_chocolatey:
        name: "{{ item.package_name }}"
        state: absent
{% endfor %}

期望的Playbook输出

---
- name: Playbook for VM 52
  hosts: all
  become: true
  tasks:

    - name: Install Google Chrome
      win_chocolatey:
        name: "googlechrome"
        state: present

解决方案

核心问题是:数据库中install字段存储的是嵌套JSON结构——外层是JSON数组,数组内的元素又是转义后的JSON字符串。当前代码仅解析了外层数组,但数组内的字符串未被解析为字典,导致Jinja2无法通过item.name访问属性。

修改main函数中install和uninstall的解析逻辑,对数组内的每个元素再执行一次JSON解析:

def main():
    data = fetch_data_from_mysql()
    
    for record in data:
        vm_id = record['vm_id']
        # 解析外层数组后,逐个解析内部的JSON字符串
        install = [json.loads(item) for item in json.loads(record['install'])] if record['install'] else []
        uninstall = [json.loads(item) for item in json.loads(record['uninstall'])] if record['uninstall'] else []

        # Print statements to verify the JSON parsing
        print(f"VM ID: {vm_id}")
        print(f"Install Data: {json.dumps(install, indent=4)}")
        print(f"Uninstall Data: {json.dumps(uninstall, indent=4)}")   
        
        context = {
            'vm_id': vm_id,
            'install': install,
            'uninstall': uninstall
        }

        playbook_filename = f'playbook_vm_{vm_id}.yml'
        create_dynamic_playbook('playbook_template.yml.j2', playbook_filename, context)
        print(f"Playbook {playbook_filename} created successfully.")

修改后,install会被解析为字典数组,Jinja2模板就能正确访问item.name和item.package_name,生成符合预期的Playbook。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:23:11