实现Chef run_list转标签自动化:将嵌套JSON的dict值提升一级
嘿,隔了多年捡回Python有点生疏太正常啦!我帮你一步步搞定这个Chef run_list的字典转换问题,保证清晰易懂。
核心思路拆解
你现在的需求很明确:把嵌套字典里的主机名直接和它对应的expanded_run_list值绑定,去掉中间那层多余的键,同时完全保留原值的类型(None、字符串、列表都不变)。咱们不需要做复杂的类型转换,只需要精准提取对应的值就行。
针对你现有数据的代码实现
假设你已经通过os.system导出并加载了data(就是你给出的那些嵌套字典示例),用这段代码就能完成转换:
import json import os # 你原有的数据导出代码(可以保留) os.system("knife search '*:*' -a expanded_run_list -F json > /tmp/hostname_runlist.json") data = json.load(open('/tmp/hostname_runlist.json')) # 核心转换逻辑 cleaned_runlists = {} for entry in data: # 每个entry是类似 {'abc.com': {'expanded_run_list': None}} 的单键字典 # 快速取出唯一的主机名(因为每个entry只有一个键) hostname = next(iter(entry.keys())) # 直接提取expanded_run_list的值,原封不动存入新字典 run_list_value = entry[hostname]['expanded_run_list'] cleaned_runlists[hostname] = run_list_value
关键代码解释
next(iter(entry.keys())):因为每个entry里只有一个键(主机名),这个方法能高效取出这个唯一键,比循环遍历更简洁。entry[hostname]['expanded_run_list']:直接从嵌套字典中提取目标值,没有做任何类型转换,所以原有的None、字符串、列表类型都会完整保留,完全符合你的要求。
可选优化:不用临时文件更高效
你原来用os.system生成临时文件的方式可以优化,用subprocess模块直接捕获命令输出,省去写文件的步骤,代码更干净:
import json import subprocess # 直接执行knife命令并捕获JSON输出 result = subprocess.run( ["knife", "search", "*:*", "-a", "expanded_run_list", "-F", "json"], capture_output=True, text=True, check=True # 命令执行失败时会抛出异常,方便排查问题 ) # 解析JSON数据 data = json.loads(result.stdout) # 注意:如果knife返回的原始数据是带`rows`字段的结构(比如{"rows": [...]}),需要先提取rows: # data = data['rows'] # 此时每个entry的结构可能是{"name": "abc.com", "attributes": {"expanded_run_list": None}},提取方式要调整为: # hostname = entry['name'] # run_list_value = entry['attributes']['expanded_run_list'] # 后续转换逻辑和之前一致 cleaned_runlists = {} for entry in data: hostname = next(iter(entry.keys())) cleaned_runlists[hostname] = entry[hostname]['expanded_run_list']
验证转换结果
用你给出的示例数据测试,转换后的cleaned_runlists会是:
{ 'abc.com': None, 'foo.com': 'base::default', '123.com': ['utils::default', 'base::default'] }
完全匹配你想要的格式,所有值的类型也都保留了下来。
内容的提问来源于stack exchange,提问作者hobbes
相关产品推荐
相关产品推荐

