Ansible动态生成CSV表头适配SNMP主机数量需求
解决Ansible采集SNMP主机数据动态生成CSV表头的方案
方案一:动态生成CSV表头(推荐)
通过先汇总所有设备的SNMP主机字段,再基于唯一字段生成表头,完美匹配实际采集数据:
采集并处理单设备SNMP主机数据
将每个设备的SNMP主机列表转换为带序号的键值对(如snmp_host_1: 192.168.1.1),方便后续字段汇总:- name: 采集设备SNMP主机数据 snmp_facts: host: "{{ inventory_hostname }}" version: v2c community: public register: snmp_raw_data - name: 格式化SNMP主机为带序号的键值对 set_fact: formatted_snmp_hosts: > {% set host_list = snmp_raw_data.snmp_hosts | default([]) %} {% set result = {} %} {% for idx, host in enumerate(host_list, start=1) %} {% set _ = result.update({'snmp_host_' ~ idx: host}) %} {% endfor %} {{ result }}汇总所有设备的SNMP字段
在本地节点汇总所有设备的字段名,去重后作为最终表头:- name: 收集所有设备的SNMP字段 set_fact: all_snmp_fields: "{{ all_snmp_fields | default([]) + formatted_snmp_hosts.keys() | list }}" delegate_to: localhost run_once: true - name: 生成唯一有序的表头字段 set_fact: final_csv_headers: "{{ all_snmp_fields | unique | sort }}" delegate_to: localhost run_once: true生成CSV文件
使用Jinja2模板,基于动态表头写入所有设备数据,缺失字段自动留空:- name: 生成最终CSV报告 template: src: snmp_report.csv.j2 dest: ./network_snmp_hosts.csv delegate_to: localhost run_once: true模板文件
snmp_report.csv.j2内容:{{ final_csv_headers | join(',') }} {% for device in groups['network_devices'] %} {% set device_data = hostvars[device]['formatted_snmp_hosts'] | default({}) %} {{ final_csv_headers | map('extract', device_data, '') | join(',') }} {% endfor %}
方案二:填充默认值后移除空列
如果无法提前汇总字段,可先按预估最大数量定义表头,填充缺失值后再清理空列:
预定义表头并填充数据
假设最多可能有10个SNMP主机,预定义表头后,对每个设备的缺失字段填充空值:- name: 预定义初始CSV表头 set_fact: temp_headers: "{{ ['snmp_host_' ~ idx for idx in range(1, 11)] }}" delegate_to: localhost run_once: true - name: 填充设备SNMP数据(不足10个则补空) set_fact: filled_snmp_data: > {% set data = formatted_snmp_hosts | default({}) %} {% set result = {} %} {% for header in temp_headers %} {% set _ = result.update({header: data.get(header, '')}) %} {% endfor %} {{ result }}移除全空列
使用Python脚本过滤掉所有行都为空的列,生成最终CSV:- name: 清理CSV空列 shell: | python3 - << 'EOF' import csv import sys input_path = sys.argv[1] output_path = sys.argv[2] with open(input_path, 'r') as f: rows = list(csv.reader(f)) # 筛选非空列索引 valid_cols = [] for col_idx in range(len(rows[0])): if any(row[col_idx].strip() for row in rows[1:]): valid_cols.append(col_idx) # 生成过滤后的数据 filtered_rows = [[row[idx] for idx in valid_cols] for row in rows] with open(output_path, 'w', newline='') as f: csv.writer(f).writerows(filtered_rows) EOF ./temp_snmp_report.csv ./final_snmp_report.csv delegate_to: localhost run_once: true
注意事项
- 方案一无需事后处理,效率更高,适合字段波动大的场景;方案二适合采集任务分散、无法提前汇总字段的情况。
- 不同厂商设备的SNMP返回结构可能有差异,需根据实际返回调整
formatted_snmp_hosts的处理逻辑。
内容的提问来源于stack exchange,提问作者Yashas K.M
相关产品推荐
相关产品推荐

