借助Ansible从Inventory API返回内容解析扁平化清单
需求说明
需要解析API返回的CSV格式字符串,生成按环境分组、包含唯一服务器名的Ansible Inventory清单。原始API返回数据如下:
""Name","Status","Environnement",
"srvin-host1","Active","PRODUCTION",
"srvin-host1","Active","PRODUCTION",
"srvin-host1","Active","PRODUCTION",
"srvin-host10","Active","PRODUCTION",
"srvin-host2","Active","PRODUCTION",
"srvin-host2","Active","PRODUCTION",
"srvin-host3","Active","PRODUCTION""
以下提供两种实现方案:Ansible原生任务方案(无需额外Python脚本)、入门级Python脚本方案(适合刚接触Python的场景)。
方案一:Ansible原生任务实现
步骤1:清理原始API返回字符串
先将带格式的原始字符串转换为标准CSV格式:
- name: 清理API返回的原始字符串 set_fact: cleaned_csv: "{{ api_raw_data | regex_replace('^\"|\"$', '') | regex_replace('<br />', '\n') }}"
说明:api_raw_data替换为存储API返回结果的变量名,此步骤去掉首尾冗余引号,将<br />替换为换行符,得到标准CSV文本。
步骤2:解析CSV并去重
将CSV文本转换为结构化列表,并去除重复的主机条目:
- name: 解析CSV并去重 set_fact: inventory_list: "{{ cleaned_csv | split('\n') | map('trim') | reject('equalto', '') | map('split', ',') | map('map', 'regex_replace', '^\"|\"$', '') | list | unique }}"
说明:依次完成行分割、去除空行、字段分割、去除字段引号、去重操作,最终得到包含表头和唯一主机条目的列表。
步骤3:按环境分组构建Inventory结构
循环处理主机条目,按环境名称分组:
- name: 按环境分组构建Inventory字典 set_fact: grouped_inventory: "{{ grouped_inventory | default({}) | combine({ item[2]: (grouped_inventory[item[2]] | default([])) + [item[0]] }) }}" loop: "{{ inventory_list[1:] }}" # 跳过第一行表头
说明:遍历所有主机条目(跳过表头),将每个主机名添加到对应环境的列表中,最终得到{ "PRODUCTION": ["srvin-host1", "srvin-host10", ...] }的结构。
步骤4:生成Inventory文件
将分组后的结构写入静态Inventory文件:
- name: 生成Inventory文件 copy: content: | {% for env, hosts in grouped_inventory.items() %} [{{ env }}] {% for host in hosts %} {{ host }} {% endfor %} {% endfor %} dest: ./inventory.ini
执行完后,会在当前目录生成inventory.ini,内容如下:
[PRODUCTION] srvin-host1 srvin-host10 srvin-host2 srvin-host3
方案二:入门级Python脚本实现
如果更倾向用Python处理,以下是简洁易懂的脚本(适合刚接触Python的用户):
# 替换为API返回的原始字符串 raw_api_data = '''""Name","Status","Environnement", "srvin-host1","Active","PRODUCTION", "srvin-host1","Active","PRODUCTION", "srvin-host1","Active","PRODUCTION", "srvin-host10","Active","PRODUCTION", "srvin-host2","Active","PRODUCTION", "srvin-host2","Active","PRODUCTION", "srvin-host3","Active","PRODUCTION""''' # 1. 清理数据:去掉首尾引号,替换换行标签,分割成每行 cleaned_lines = raw_api_data.strip('"').replace('<br />', '\n').split('\n') # 2. 按环境分组并去重 inventory_groups = {} for line in cleaned_lines: line = line.strip().rstrip(',') # 去掉行尾逗号和空白 if not line: continue # 拆分字段并去掉引号 parts = [field.strip('"') for field in line.split(',')] if parts[0] == 'Name': # 跳过表头行 continue host_name = parts[0] env_name = parts[2] # 用集合自动去重 if env_name not in inventory_groups: inventory_groups[env_name] = set() inventory_groups[env_name].add(host_name) # 3. 生成Inventory格式内容并保存 with open('inventory.ini', 'w', encoding='utf-8') as f: for env, hosts in inventory_groups.items(): f.write(f'[{env}]\n') # 按主机名排序后写入 for host in sorted(hosts): f.write(f'{host}\n') print("Inventory文件已生成:inventory.ini")
运行脚本后,同样会生成标准的按环境分组的Inventory文件。
对原有尝试的说明
你之前的Ansible任务仅处理了单个主机条目(var2的三个元素),没有遍历所有行数据,也未做去重和分组操作,因此无法生成完整的分组清单。上述方案解决了这些问题,实现了从原始数据到最终Inventory的完整流程。
内容的提问来源于stack exchange,提问作者ElBaBa

