Um Outputs von Kommandos z.B. von Cisco zu parsen in Ansible kann man TEXTFSM verwenden. Dazu muss neben Ansible das textfsm Modul mit pip installiert werden.
TEXTFSM ist ein Template basierender Parser für Outputs.
Installation der benötigten Pakete:
python -m virtualenv venv source venv/bin/activate pip install ansible ansible-pylibssh textfsm
Beispiel TEXTFSM Parser Datei inventory_cisco_ios.textfsm:
Für viele Netzwerk Hersteller wie z.B. Cisco gibt es bereits fertige Templates, ich habe das Beispiel hier von networktocode/ntc-templates (Github), als Fork direkt bei mir lanbugs/ntc-templates: TextFSM templates for parsing show commands of network devices (github.com) in Github.
Value NAME (.*)
Value DESCR (.*)
Value PID (([\S+]+|.*))
Value VID (.*)
Value SN ([\w+\d+]+)
Start
^NAME:\s+"${NAME}",\s+DESCR:\s+"${DESCR}"
^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
^PID:\s+,.*VID:\s+${VID},.*SN: -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID},.*SN: -> Record
^PID:\s+,.*VID:\s+${VID},.*SN:\s+${SN} -> Record
^PID:\s+${PID}.*,.*VID:\s+${VID}.*
^PID:\s+,.*VID:\s+${VID}.*
^.*SN:\s+${SN} -> Record
^.*SN: -> Record
# Capture time-stamp if vty line has command time-stamping turned on
^Load\s+for\s+
^Time\s+source\s+isBeispiel Ansible-Playbook collect_inventory.yml:
Verwendet wird das Modul ansible.utils.cli_parse und als parser ansible.utils.textfsm. Als template_path wird die textfsm Datei angegeben welche den Output parsen kann.
---
- name: Collect invenory of device
hosts: testswitch
gather_facts: False
vars:
ansible_connection: network_cli
ansible_network_os: ios
connection: network_cli
tasks:
- name: Collect inventory
ansible.utils.cli_parse:
command: show inventory
parser:
name: ansible.utils.textfsm
template_path: inventory_cisco_ios.textfsm
register: inv
- name: Debug
debug:
msg: "{{ inv }}"Beispiel Ansible Inventory inventory.ini:
[devices] testswitch ansible_host=10.1.1.1 ansible_user=cisco ansible_ssh_pass=cisco
Output:
(venv) lab@labhost:~$ ansible-playbook -i inventory.ini collect_inventory.yml
PLAY [Collect invenory of device] ********************************************************************************************************************************************
TASK [Gather invenory] ***************************************************************************************************************************************************
ok: [testswitch]
TASK [Debug] *************************************************************************************************************************************************************
ok: [testswitch] => {
"msg": {
"changed": false,
"failed": false,
"parsed": [
{
"DESCR": "WS-C3560CG-8PC-S",
"NAME": "1",
"PID": "WS-C3560CG-8PC-S",
"SN": "FOC1234A0ZZ",
"VID": "V03 "
}
],
"stdout": "NAME: \"1\", DESCR: \"WS-C3560CG-8PC-S\"\nPID: WS-C3560CG-8PC-S , VID: V03 , SN: FOC1234A0ZZ",
"stdout_lines": [
"NAME: \"1\", DESCR: \"WS-C3560CG-8PC-S\"",
"PID: WS-C3560CG-8PC-S , VID: V03 , SN: FOC1234A0ZZ"
]
}
}
PLAY RECAP ***************************************************************************************************************************************************************
testswitch : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 In inv.parsed ist jetzt eine Liste von Dictionarys mit den geparsten Daten. In inv.stdout_lines sind die originalen der Rückgabe.
Jetzt könnte man z.B. das in ein CSV File schreiben, hier eine Ergänzung für das Playbook:
- name: Add to report
lineinfile:
insertafter: EOF
dest: inv_report.txt
line: "'{{ inventory_hostname }}','{{ item.NAME|default('no name') }}','{{ item.DESCR|default('no descr') }}','{{ item.PID|default('no pid') }}','{{ item.SN|default('no sn') }}','{{ item.VID|default('no vid') }}'"
with_list: "{{ inv.parsed }}"
when: inv.failed is false
delegate_to: localhost