A partir de cette commande show interface
:
rtr2#show interfaces
GigabitEthernet1 is up, line protocol is up
Hardware is CSR vNIC, address is 0e56.1bf5.5ee2 (bia 0e56.1bf5.5ee2)
Internet address is 172.17.16.140/16
MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec,
reliability 255/255, txload 1/255, rxload 1/255
Encapsulation ARPA, loopback not set
Keepalive set (10 sec)
Full Duplex, 1000Mbps, link type is auto, media type is Virtual
output flow-control is unsupported, input flow-control is unsupported
ARP type: ARPA, ARP Timeout 04:00:00
.
.
<output omitted for brevity>
Il s’agit d’obtenir des données structurées :
TASK [DISPLAY THE PARSED DATA] **************************************************************************************************************************************************************
ok: [rtr1] => {
"interface_facts": [
{
"GigabitEthernet1": {
"config": {
"description": null,
"mtu": 1500,
"name": "GigabitEthernet1",
"type": "CSR"
}
}
},
{
"Loopback0": {
"config": {
.
.
<output omitted for brevity>
La plupart des périphériques fondés sur la “ligne de commande (CLI)” supportent la commande show
. Ces données sont bien formatées pour la lisibilité des humains mais la présentation est beaucoup moins facile à lire pour nos ordinateurs qui ont besoin de données structurées. Les résultats des commandes show
devraient être transformés en types de données que les machines pourraient interpréter et à travers lesquelles elles pourraient naviguer.
Ansible network-engine est un rôle qui supporte deux “traducteurs” : command_parser
et textfsm_parser
. Ce sont des modules qui sont contruits dans le rôle network-engine
pour transformer une entrée en texte brut (bien formaté) en donnée structurée.
Pour rappel on peut démarrer une automation avec Ansible à l’aide de deux fichiers :
Voici la structure de deux rôles “common” et “ospf”. Chacun est organisé par “convention” en dossiers et fichiers convenus.
site.yml
roles/
common/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
ospf/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
Le fichier site.yml
(on choisit ce que l’on veut comme nom de fichier pour un livre de jeu) est un livre de jeu qui joue les deux rôles.
# site.yml
---
- hosts: routers
roles:
- common
- ospf
Ansible Galaxy est un service qui concentre les rôles Ansible à usage de découverte, de ré-utilisation et de partage.
Vous pouvez démarrer votre gestion Ansible à partir de rôles révisés et maintenus par la communauté Ansible, comme proposé ici avec le rôle ansible-network.network-engine
.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
Le rôle network-engine peut être installé à partir d’Ansible Galaxy
Voyez le site http://galaxy.ansible.com.
Sur la plupart des périphériques du réseau, la commande show
convient pour la lecture des yeux mais certainement pas pour les données structurées.
Le rôle Ansible network-engine fournit deux outils de traitement :
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
tasks:
- name: CAPTURE SHOW INTERFACES
ios_command:
commands:
- show interfaces
register: output
- name: PARSE THE RAW OUTPUT
command_parser:
file: "parsers/show_interfaces.yml"
content: "{{ output.stdout[0] }}"
Voici à quoi ressemble la sortie d’une commande show interfaces
sur un périphérique Cisco IOS :
rtr2#show interfaces
GigabitEthernet1 is up, line protocol is up
Hardware is CSR vNIC, address is 0e56.1bf5.5ee2 (bia 0e56.1bf5.5ee2)
Internet address is 172.17.16.140/16
MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec,
reliability 255/255, txload 1/255, rxload 1/255
Encapsulation ARPA, loopback not set
Keepalive set (10 sec)
Full Duplex, 1000Mbps, link type is auto, media type is Virtual
output flow-control is unsupported, input flow-control is unsupported
ARP type: ARPA, ARP Timeout 04:00:00
Last input 00:00:00, output 00:00:00, output hang never
Last clearing of "show interface" counters never
Input queue: 0/375/0/0 (size/max/drops/flushes); Total output drops: 0
Queueing strategy: fifo
Output queue: 0/40 (size/max)
5 minute input rate 1000 bits/sec, 1 packets/sec
5 minute output rate 1000 bits/sec, 1 packets/sec
208488 packets input, 22368304 bytes, 0 no buffer
Received 0 broadcasts (0 IP multicasts)
0 runts, 0 giants, 0 throttles
0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
0 watchdog, 0 multicast, 0 pause input
250975 packets output, 40333671 bytes, 0 underruns
0 output errors, 0 collisions, 1 interface resets
0 unknown protocol drops
0 babbles, 0 late collision, 0 deferred
0 lost carrier, 0 no carrier, 0 pause output
0 output buffer failures, 0 output buffers swapped out
Loopback0 is up, line protocol is up
Hardware is Loopback
Internet address is 192.168.2.102/24
MTU 1514 bytes, BW 8000000 Kbit/sec, DLY 5000 usec,
reliability 255/255, txload 1/255, rxload 1/255
Encapsulation LOOPBACK, loopback not set
Keepalive set (10 sec)
.
.
<output omitted for brevity>
Imaginons que votre objectif est de préparer une liste de toutes les interfaces qui sont up, leur paramètre MTU et leur description. Imaginez que vous disposiez de 10 périphériques : il jouable de se connecter sur chacun de manière manuelle, à l’ancienne à moins que de passer par Bash, Python et SSH. Mais combien d’heure passerez-vous pour vous connecter à 150 périphériques ?
Dans ce lab, nous allons apprendre à automatiser ce scénario avec Ansible.
Veuillez commencer par créer un livre de jeu nommé interface_report.yml
et d’y ajouter la définition du jeux suivants.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
Ensuite, il s’agira d’ajouter le rôle ansible-network.network-engine
. Un rôle n’est rien d’autre qu’un niveau d’abstraction plus élevé du livre de jeu. Pensez qu’un rôle Ansible est un livre de jeu abstrait qui comprend des tâches répititives et spécifiques, à ré-utiliser. Mais avant tout, il est nécessaire d’installer localement le rôle.
ansible-galaxy install ansible-network.network-engine
Ce rôle Ansible ansible-network.network-engine
rend le module command_parser
disponible dans la suite du livre de jeu. Il s’agit de l’invoquer dans le livre de jeu avec la directive roles:
dans un élément d’un liste.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
On peut alors ajouter une première tâche qui exécutera la commande show interfaces
sur tous les routeurs et qui enregistrera la sortie dans une variable nommée “output
”.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
tasks:
- name: CAPTURE SHOW INTERFACES
ios_command:
commands:
- show interfaces
register: output
N’hésitez pas à exécuter le livre de jeu en mode verbeux pour voir le résultat.
La prochaine tâche consiste à envoyer les données brutes venant de la tâche précédente auprès du module command_parser
.
Note: Le fichier du parser, en argument du module, est un fichier YAML semblable à la structure d’un livre de jeu Ansible.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
tasks:
- name: CAPTURE SHOW INTERFACES
ios_command:
commands:
- show interfaces
register: output
- name: PARSE THE RAW OUTPUT
command_parser:
file: "parsers/show_interfaces.yaml"
content: "{{ output.stdout[0] }}"
Le module command_parser
référence un fichier show_interfaces.yaml
situé dans le dossier parsers
. On peut l’obtenir ici. Voici la procédure pour le récupérer.
mkdir parsers
curl https://raw.githubusercontent.com/goffinet/networking-workshop/master/parsers/show_interfaces.yaml -o parsers/show_interfaces.yaml
Notez que ce fichier utilise des expressions rationnelles pour capturer les données intéressantes et les retourne dans une variable nommée interface_facts
.
Veuillez ajouter une nouvelle tâche afin de visualiser ce qui retourné par le module command_parser
.
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
tasks:
- name: CAPTURE SHOW INTERFACES
ios_command:
commands:
- show interfaces
register: output
- name: PARSE THE RAW OUTPUT
command_parser:
file: "parsers/show_interfaces.yaml"
content: "{{ output.stdout[0] }}"
- name: DISPLAY THE PARSED DATA
debug:
var: interface_facts
Veuillez exécuter le livre de jeu mais seulement sur un seul routeur comme rtr1
pour limiter la taille de la sortie.
ansible-playbook interface_report.yml --limit rtr1
PLAY [GENERATE INTERFACE REPORT] ************************************************************************************************************************************************************
TASK [CAPTURE SHOW INTERFACES] **************************************************************************************************************************************************************
ok: [rtr1]
TASK [PARSE THE RAW OUTPUT] *****************************************************************************************************************************************************************
ok: [rtr1]
TASK [DISPLAY THE PARSED DATA] **************************************************************************************************************************************************************
ok: [rtr1] => {
"interface_facts": [
{
"GigabitEthernet1": {
"config": {
"description": null,
"mtu": 1500,
"name": "GigabitEthernet1",
"type": "CSR"
}
}
},
{
"Loopback0": {
"config": {
"description": null,
"mtu": 1514,
"name": "Loopback0",
"type": "Loopback"
}
}
},
{
"Loopback1": {
"config": {
"description": null,
"mtu": 1514,
"name": "Loopback1",
"type": "Loopback"
}
}
},
{
"Tunnel0": {
"config": {
"description": null,
"mtu": 9976,
"name": "Tunnel0",
"type": "Tunnel"
}
}
},
{
"Tunnel1": {
"config": {
"description": null,
"mtu": 9976,
"name": "Tunnel1",
"type": "Tunnel"
}
}
},
{
"VirtualPortGroup0": {
"config": {
"description": null,
"mtu": 1500,
"name": "VirtualPortGroup0",
"type": "Virtual"
}
}
}
]
}
PLAY RECAP **********************************************************************************************************************************************************************************
rtr1 : ok=3 changed=0 unreachable=0 failed=0
Formidable ! Le livre de jeu transforme le texte brut de la commande show
en données structurées : un liste de dictionnaires où chacun décrit les éléments nécessaires à l’élaboration d’un rapport.
Il s’agit de créer un dossier qui hébergera le rapport des périphériques.
mkdir intf_reports
Dans cette étape, on propose d’utiliser le module Ansible template
pour générer le rapport avec les données collectées dans les tâches précédentes. Il s’agit de la même technique que celle utilisée dans le lab précédent qui consiste à créer un rapport pour chaque périphérique et un rapport consolidé avec le module Ansible assemble
---
- name: GENERATE INTERFACE REPORT
hosts: cisco
gather_facts: no
connection: network_cli
roles:
- ansible-network.network-engine
tasks:
- name: CAPTURE SHOW INTERFACES
ios_command:
commands:
- show interfaces
register: output
- name: PARSE THE RAW OUTPUT
command_parser:
file: "parsers/show_interfaces.yaml"
content: "{{ output.stdout[0] }}"
#- name: DISPLAY THE PARSED DATA
# debug:
# var: interface_facts
- name: GENERATE REPORT FRAGMENTS
template:
src: interface_facts.j2
dest: intf_reports/{{inventory_hostname}}_intf_report.md
- name: GENERATE A CONSOLIDATED REPORT
assemble:
src: intf_reports/
dest: interfaces_report.md
delegate_to: localhost
run_once: yes
Note: la tâche “DISPLAY THE PARSED DATA” a été commentée.
Voici ce modèle templates/interface_facts.j2
à créer dans le dossier templates/
:
{{ inventory_hostname.upper() }}
{{ '-' * inventory_hostname|length }}
{% for intf in interface_facts %}
{% for intf_key,intf_value in intf.items() %}
{{intf_key}}:
{% for k,v in intf_value.items() %}
Description: {{v.description}}
Name: {{v.name}}
MTU: {{v.mtu}}
{% endfor %}
{% endfor %}
{% endfor %}
Veuillez lancer ce livre de jeu :
ansible-playbook interface_report.yml
PLAY [GENERATE INTERFACE REPORT] ************************************************************************************************************************************************************
TASK [CAPTURE SHOW INTERFACES] **************************************************************************************************************************************************************
ok: [rtr1]
ok: [rtr3]
ok: [rtr4]
ok: [rtr2]
TASK [PARSE THE RAW OUTPUT] *****************************************************************************************************************************************************************
ok: [rtr3]
ok: [rtr2]
ok: [rtr1]
ok: [rtr4]
TASK [GENERATE REPORT FRAGMENTS] ************************************************************************************************************************************************************
changed: [rtr4]
changed: [rtr2]
changed: [rtr3]
changed: [rtr1]
TASK [GENERATE A CONSOLIDATED REPORT] *******************************************************************************************************************************************************
changed: [rtr3]
ok: [rtr1]
ok: [rtr4]
ok: [rtr2]
PLAY RECAP **********************************************************************************************************************************************************************************
rtr1 : ok=4 changed=1 unreachable=0 failed=0
rtr2 : ok=4 changed=1 unreachable=0 failed=0
rtr3 : ok=4 changed=2 unreachable=0 failed=0
rtr4 : ok=4 changed=1 unreachable=0 failed=0
La commande cat
nous offre le résultat attendu.
cat interfaces_report.md
RTR1
----
GigabitEthernet1:
Description:
Name: GigabitEthernet1
MTU: 1500
Loopback0:
Description:
Name: Loopback0
MTU: 1514
Loopback1:
Description:
Name: Loopback1
MTU: 1514
Tunnel0:
Description:
Name: Tunnel0
MTU: 9976
Tunnel1:
Description:
Name: Tunnel1
MTU: 9976
VirtualPortGroup0:
Description:
Name: VirtualPortGroup0
MTU: 1500
RTR2
----
GigabitEthernet1:
Description:
Name: GigabitEthernet1
MTU: 1500
Loopback0:
Description:
Name: Loopback0
MTU: 1514
Loopback1:
Description:
Name: Loopback1
MTU: 1514
.
.
<output omitted for brevity>