[英]ansible CSV header options when appending with for loop
i'm trying to gather.network devices data using ansible and add to csv file which is working fine for me but then now i would like to have the headers to the match to whats been gathered.我正在尝试使用 ansible 收集网络设备数据并添加到 csv 文件中,该文件对我来说工作正常,但现在我想让标头与所收集的内容相匹配。
- name: Playbook to collect ntp,snmp_facts and put into csv file
hosts: all
connection: network_cli
gather_facts: true
# check_mode: yes
vars:
output_path: "./reports/"
filename: "device_report_{{ date }}.csv"
vendor: CISCO
tasks:
- name: CSV - Generate output filename
set_fact: date="{{lookup('pipe','date +%Y%m%d')}}"
run_once: true
- name: CSV - Create file and set the header
lineinfile:
dest: "{{ output_path }}/{{ filename }}"
**line: hostname,ip_address,image,iostype,model,serialnum,system,version,ntp_server_1,ntp_server_2,vrf,snmp_server_1,snmp_server_2,snmp_server_3,snmp_server_4,snmp_server_5,snmp_server_6**
create: true
state: present
- import_tasks: /path/playbooks/facts/ntp_facts/ntp_facts_get.yml
# - import_tasks: /path/playbooks/facts/snmp_facts/snmp_facts_get_2960.yml
# - import_tasks: /path/playbooks/facts/snmp_facts/snmp_facts_get_not_2960.yml
- import_tasks: /path/playbooks/facts/snmp_facts/snmp_another_test.yml
- import_tasks: /path/playbooks/facts/dns_facts/dns_facts_domain_name_get.yml
- name: CSV - Getting all the data just before printing to csv
set_fact:
csv_tmp: >
{{ ansible_net_hostname|default('N/A') }},
{{ ansible_host|default('N/A') }},
{{ ansible_net_image|default('N/A') }},
{{ ansible_net_iostype|default('N/A') }},
{{ ansible_net_model|default('N/A') }},
{{ ansible_net_serialnum|default('N/A') }},
{{ ansible_net_system|default('N/A') }},
{{ ansible_net_version|default('N/A') }},
{{ ntp_servers.gathered.servers[0].server|default('N/A') }},
{{ ntp_servers.gathered.servers[1].server|default('N/A') }},
{{ ntp_servers.gathered.servers[0].vrf|default('N/A') }},
{% set snmp_list = [] %}
{% for snmp_host in snmp_hosts %}
{% set snmp_list = snmp_list.append(snmp_host.host ~ ',' ~ snmp_host.version) %}
{% endfor %}
{{ snmp_list|join(',') }},
{{ domain_name[0]|default('N/A') }},
- name: check whats up with this csv_tmp
debug:
var: csv_tmp
- name: CSV - Write information into .csv file
lineinfile:
insertafter: EOF
dest: "{{ output_path }}/{{ filename }}"
line: "{{ csv_tmp }}"
- name: CSV - Blank lines removal
lineinfile:
path: "./{{ output_path }}/{{ filename }}"
state: absent
regex: '^\s*$'
when appending for each device using csv_tmp i have the for loop for snmp当使用 csv_tmp 为每个设备附加时,我有 snmp 的 for 循环
{% for snmp_host in snmp_hosts %}
{% set snmp_list = snmp_list.append(snmp_host.host ~ ',' ~ snmp_host.version) %}
{% endfor %}
{{ snmp_list|join(',') }},
So i would not know how many snmp hosts are configured so i was thinking if there are some better ways to have this achieved or somehow have a dynamic option to generate header or have an option to make sure that each of value {{ ansible.net_hostname|default('N/A') }},
into certain specified values first and then remove any empty column.所以我不知道配置了多少 snmp 主机,所以我在想是否有更好的方法来实现这一点,或者有一个动态选项来生成 header 或者有一个选项来确保每个值
{{ ansible.net_hostname|default('N/A') }},
首先转换为特定的指定值,然后删除任何空列。
I have a bit of time constraint so reaching out here for help.我有一点时间限制,所以在这里寻求帮助。
Given the inventory for testing给定测试库存
shell> cat hosts
test_11 ansible_host=10.1.0.61
test_13 ansible_host=10.1.0.63
Create a dictionary first.首先创建字典。 Declare the below variables in vars .
在vars中声明以下变量。 For example, in group_vars
例如,在group_vars
shell> cat group_vars/all/csv_content.yml
csv_content_dict_str: |
hostname: {{ ansible_net_hostname|d('N/A') }}
ip_address: {{ ansible_host|d('N/A') }}
image: {{ ansible_net_image|d('N/A') }}
iostype: {{ ansible_net_iostype|d('N/A') }}
model: {{ ansible_net_model|d('N/A') }}
serialnum: {{ ansible_net_serialnum|d('N/A') }}
system: {{ ansible_net_system|d('N/A') }}
version: {{ ansible_net_version|d('N/A') }}
ntp_server_1: {{ ntp_servers.gathered.servers[0].server|d('N/A') }}
ntp_server_2: {{ ntp_servers.gathered.servers[1].server|d('N/A') }}
vrf: {{ ntp_servers.gathered.servers[0].vrf|d('N/A') }}
{% for snmp_host in snmp_hosts|d([]) %}
snmp_server_{{ loop.index }}: {{ snmp_host.host }}
snmp_server_version_{{ loop.index }}: {{ snmp_host.version }}
{% endfor %}
domain_name: {{ domain_name[0]|d('N/A') }}
csv_content_dict: "{{ csv_content_dict_str|from_yaml }}"
csv_content: |
{{ csv_content_dict.keys()|join(',') }}
{{ csv_content_dict.values()|join(',') }}
Without any facts collected, this gives在没有收集任何事实的情况下,这给出了
ok: [test_11] =>
csv_content_dict:
domain_name: N/A
hostname: N/A
image: N/A
iostype: N/A
ip_address: 10.1.0.61
model: N/A
ntp_server_1: N/A
ntp_server_2: N/A
serialnum: N/A
system: N/A
version: N/A
vrf: N/A
ok: [test_13] =>
csv_content_dict:
domain_name: N/A
hostname: N/A
image: N/A
iostype: N/A
ip_address: 10.1.0.63
model: N/A
ntp_server_1: N/A
ntp_server_2: N/A
serialnum: N/A
system: N/A
version: N/A
vrf: N/A
Write the files写文件
- copy:
dest: "{{ output_path }}/{{ filename }}"
content: "{{ csv_content }}"
gives给
shell> ssh admin@test_11 cat /tmp/reports/device_report_2023-01-22.csv
hostname,ip_address,image,iostype,model,serialnum,system,version,ntp_server_1,ntp_server_2,vrf,domain_name
N/A,10.1.0.61,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A
shell> ssh admin@test_13 cat /tmp/reports/device_report_2023-01-22.csv
hostname,ip_address,image,iostype,model,serialnum,system,version,ntp_server_1,ntp_server_2,vrf,domain_name
N/A,10.1.0.63,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A
shell> cat write_report.yml - hosts: all vars: output_path: /tmp/reports filename: "device_report_{{ date }}.csv" tasks: - set_fact: date: "{{ '%Y-%m-%d'|strftime }}" run_once: true - file: state: directory path: "{{ output_path }}" - block: - debug: var: csv_content_dict - debug: msg: | {{ csv_content }} when: debug|d(false)|bool - copy: dest: "{{ output_path }}/{{ filename }}" content: "{{ csv_content }}"
shell> cat host_vars/test_11/test_network_facts.yml
snmp_hosts:
- host: snmp1.example.com
version: SNMPv3
- host: snmp2.example.com
version: SNMPv3
Create, or collect facts.创建或收集事实。 For example, create host_vars for testing
例如,创建host_vars用于测试
shell> cat host_vars/test_11/test.network_facts.yml snmp_hosts: - host: snmp1.example.com version: SNMPv3 - host: snmp2.example.com version: SNMPv3
shell> ansible-playbook write_report.yml -l test_11 PLAY [all] *********************************************************************************** TASK [Gathering Facts] *********************************************************************** ok: [test_11] TASK [set_fact] ****************************************************************************** ok: [test_11] TASK [file] ********************************************************************************** ok: [test_11] TASK [debug] ********************************************************************************* skipping: [test_11] TASK [debug] ********************************************************************************* skipping: [test_11] TASK [copy] ********************************************************************************** changed: [test_11] PLAY RECAP *********************************************************************************** test_11: ok=4 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
shell> ssh admin@test_11 cat /tmp/reports/device_report_2023-01-22.csv hostname,ip_address,image,iostype,model,serialnum,system,version,ntp_server_1,ntp_server_2,vrf,snmp_server_1,snmp_server_version_1,snmp_server_2,snmp_server_version_2,domain_name N/A,10.1.0.61,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,snmp1.example.com,SNMPv3,snmp2.example.com,SNMPv3,N/A
shell> ansible-playbook read_report.yml -l test_11 PLAY [all] *********************************************************************************** TASK [Gathering Facts] *********************************************************************** ok: [test_11] TASK [set_fact] ****************************************************************************** ok: [test_11] TASK [community.general.read_csv] ************************************************************ ok: [test_11] TASK [debug] ********************************************************************************* ok: [test_11] => report.list: - domain_name: N/A hostname: N/A image: N/A iostype: N/A ip_address: 10.1.0.61 model: N/A ntp_server_1: N/A ntp_server_2: N/A serialnum: N/A snmp_server_1: snmp1.example.com snmp_server_2: snmp2.example.com snmp_server_version_1: SNMPv3 snmp_server_version_2: SNMPv3 system: N/A version: N/A vrf: N/A PLAY RECAP *********************************************************************************** test_11: ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Q: "It's overwriting every time since some hosts have 5 SNMP configured and some only 2."问: “每次都覆盖,因为有些主机配置了 5 个 SNMP,而有些主机只配置了 2 个。”
A: This can't happen if you write reports into separate files at the remote hosts.答:如果您将报告写入远程主机上的单独文件,则不会发生这种情况。 Add hours-minutes-seconds
%H-%M-%S
to the name of the CSV file在CSV文件名中加入时分秒
%H-%M-%S
- set_fact: date: "{{ '%Y-%m-%d-%H-%M-%S'|strftime }}" run_once: true
Then, a new file will be created each time you run the playbook.然后,每次运行剧本时都会创建一个新文件。 For example,
例如,
shell> ssh admin@test_13 ls -la /tmp/reports
total 34
drwxr-xr-x 2 root wheel 4 Jan 23 03:30 .
drwxrwxrwt 10 root wheel 17 Jan 23 03:30 ..
-rw-r--r-- 1 root wheel 161 Jan 22 08:30 device_report_2023-01-22.csv
-rw-r--r-- 1 root wheel 161 Jan 23 03:30 device_report_2023-01-23-04-30-00.csv
will create two files将创建两个文件
shell> ssh admin@test_11 ls -la /tmp/reports total 34 drwxr-xr-x 2 root wheel 4 Jan 23 03:30. drwxrwxrwt 13 root wheel 27 Jan 23 03:30.. -rw-r--r-- 1 root wheel 283 Jan 22 08:57 device_report_2023-01-22.csv -rw-r--r-- 1 root wheel 283 Jan 23 03:30 device_report_2023-01-23-04-30-00.csv
- file:
state: directory
path: "{{ output_path }}/{{ inventory_hostname }}"
delegate_to: localhost
The next option is to write all files to the controller (localhost).下一个选项是将所有文件写入 controller(本地主机)。 For example, create the directories
例如,创建目录
- file: state: directory path: "{{ output_path }}/{{ inventory_hostname }}" delegate_to: localhost
and write the files并写入文件
- copy: dest: "{{ output_path }}/{{ inventory_hostname }}/{{ filename }}" content: "{{ csv_content }}" delegate_to: localhost
Then, each time you run the playbook new files will be created at the controller然后,每次运行剧本时,都会在 controller 处创建新文件
shell> tree /tmp/reports/
/tmp/reports/
├── test_11
│ ├── device_report_2023-01-23-04-49-27.csv
│ └── device_report_2023-01-23-05-32-40.csv
└── test_13
├── device_report_2023-01-23-04-49-27.csv
└── device_report_2023-01-23-05-32-40.csv
2 directories, 4 files
You can easily read the reports from the files at the controller. For example, give the CSV files您可以轻松地从 controller 的文件中读取报告。例如,给 CSV 文件
shell> tree /tmp/reports/ /tmp/reports/ ├── test_11 │ ├── device_report_2023-01-23-04-49-27.csv │ └── device_report_2023-01-23-05-32-40.csv └── test_13 ├── device_report_2023-01-23-04-49-27.csv └── device_report_2023-01-23-05-32-40.csv 2 directories, 4 files
Read the files读取文件
- community.general.read_csv: path: "{{ item.src }}" register: out with_community.general.filetree: "{{ output_path }}" when: item.state == 'file' loop_control: label: "{{ item.path }}"
Declare the below variables声明以下变量
reports_lists:
test_11:
- 2023-01-23-05-32-40
- 2023-01-23-04-49-27
test_13:
- 2023-01-23-05-32-40
- 2023-01-23-04-49-27
give给
reports: test_11: 2023-01-23-04-49-27: - domain_name: N/A hostname: N/A image: N/A iostype: N/A ip_address: 10.1.0.61 model: N/A ntp_server_1: N/A ntp_server_2: N/A serialnum: N/A snmp_server_1: snmp1.example.com snmp_server_2: snmp2.example.com snmp_server_version_1: SNMPv3 snmp_server_version_2: SNMPv3 system: N/A version: N/A vrf: N/A 2023-01-23-05-32-40: - domain_name: N/A hostname: N/A image: N/A iostype: N/A ip_address: 10.1.0.61 model: N/A ntp_server_1: N/A ntp_server_2: N/A serialnum: N/A snmp_server_1: snmp1.example.com snmp_server_2: snmp2.example.com snmp_server_version_1: SNMPv3 snmp_server_version_2: SNMPv3 system: N/A version: N/A vrf: N/A test_13: 2023-01-23-04-49-27: - domain_name: N/A hostname: N/A image: N/A iostype: N/A ip_address: 10.1.0.63 model: N/A ntp_server_1: N/A ntp_server_2: N/A serialnum: N/A system: N/A version: N/A vrf: N/A 2023-01-23-05-32-40: - domain_name: N/A hostname: N/A image: N/A iostype: N/A ip_address: 10.1.0.63 model: N/A ntp_server_1: N/A ntp_server_2: N/A serialnum: N/A system: N/A version: N/A vrf: N/A
reports_lists: test_11: - 2023-01-23-05-32-40 - 2023-01-23-04-49-27 test_13: - 2023-01-23-05-32-40 - 2023-01-23-04-49-27
Example of a complete playbook to read the reports at the controller阅读 controller 报告的完整剧本示例
shell> cat read_report.yml - hosts: localhost vars: output_path: /tmp/reports reports_str: | {% for result in out.results|selectattr('list', 'defined') %} {% set _keys = result.item.path|split('/') %} {% set host = _keys|first %} {% set report = _keys|last|regex_replace('^device_report_(.*)\.csv', '\\1') %} - {{ host }}: {{ report }}: {{ result.list }} {% endfor %} reports: "{{ reports_str|from_yaml|combine(recursive=true) }}" reports_lists: "{{ dict(reports|dict2items|json_query('[].[key, value.keys(@)]')) }}" tasks: - debug: msg: "{{ item.src }}" with_community.general.filetree: "{{ output_path }}" when: - debug|d(false)|bool - item.state == 'file' loop_control: label: "{{ item.path }}" - community.general.read_csv: path: "{{ item.src }}" register: out with_community.general.filetree: "{{ output_path }}" when: item.state == 'file' loop_control: label: "{{ item.path }}" - debug: var: reports - debug: var: reports_lists
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.