[PYTHON] J'ai essayé de générer automatiquement une table de gestion des ports à partir de L2SW Config

introduction

Dans l'article précédent, j'ai présenté un exemple de génération automatique de Config à partir de la table de gestion des ports. J'ai essayé de générer automatiquement L2SW Config à partir de la table de gestion des ports + table des paramètres + modèle Jinja2

Dans certains cas, vous souhaiterez peut-être créer une table de gestion des ports à partir du fichier Config. Cette fois, j'ai essayé de générer automatiquement une table de gestion des ports au format CSV à partir du fichier de configuration L2SW à l'aide d'une bibliothèque d'analyseur Python appelée TTP (Template Text Parser).

Présentation de TTP

Pour introduire un exemple simple de Démarrage rapide dans le document tel quel, "(1) Config" est remplacé par "(2) Template". Il s'agit d'une image générée par "(3) Résultat de sortie (format JSON ou CSV)" qui est analysée à l'aide de et incluse dans {{~}}.

(1) Config

interface Loopback0
 description Router-id-loopback
 ip address 192.168.0.113/24
!
interface Vlan778
 description CPE_Acces_Vlan
 ip address 2002::fd37/124
 ip vrf CPE1
!

(2) Modèle

interface {{ interface }}
 ip address {{ ip }}/{{ mask }}
 description {{ description }}
 ip vrf {{ vrf }}

(3) Résultat de sortie (format JSON)

python


[
    [
        {
            "description": "Router-id-loopback",
            "interface": "Loopback0",
            "ip": "192.168.0.113",
            "mask": "24"
        },
        {
            "description": "CPE_Acces_Vlan",
            "interface": "Vlan778",
            "ip": "2002::fd37",
            "mask": "124",
            "vrf": "CPE1"
        }
    ]
]

Config utilisée

Cette fois, j'ai utilisé presque le même fichier Config que l'article mentionné au début. Consultez le référentiel GitHub ci-dessous pour plus de détails. Fichier de configuration --config_hqaccess1.txt

Code Python

Le flux général est le suivant.

  1. Perth Utilisez parse_config () pour afficher les résultats d'analyse au format JSON à partir de Config et du modèle.

  2. Générer une table de gestion des ports Convertissez JSON au format dictionnaire et convertissez le résultat de l'analyse de l'interface L2 en table de gestion des ports au format CSV avec write_dict_to_csv ().

Nous présenterons chaque résultat dans les éléments suivants.

portlist_generation.py


# -*- coding: utf-8 -*-
from ttp import ttp
import json
import csv

#Définir les chemins pour divers fichiers
TEMPLATE = './catalyst2960_template_ttp.txt'
PORT_LIST = './port_list_hqaccess1_ttp.csv'
CONFIG_FILENAME = './config_hqaccess1.txt'
CSV_COLUMNS = ['port_no', 'speed', 'duplex', 'mode', 'vlan', 'portfast', 'status', 'description']


def parse_config(template_file, config_filename):
    with open(config_filename, 'rt') as fc:
        data_to_parse = fc.read()

    with open(template_file, 'rt') as ft:
        ttp_template = ft.read()

    # create parser object and parse data using template:
    parser = ttp(data=data_to_parse, template=ttp_template)
    parser.parse()

    # print result in JSON format
    results = parser.result(format='json')[0]
    return results


def write_dict_to_csv(port_list, csv_columns, results):
    with open(port_list, 'w', newline='') as csvfile:   #Pour Windows, nouvelle ligne=''Est nécessaire
        writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
        writer.writeheader()
        for data in results:
            writer.writerow(data)
    return            


def main():
    results = parse_config(TEMPLATE, CONFIG_FILENAME)
    print(results)
    results_dict = json.loads(results)
    write_dict_to_csv(PORT_LIST, CSV_COLUMNS, results_dict[0]['l2_interfaces'])


if __name__ == "__main__":
    main()

Modèles et résultats en perspective

J'ai en fait créé un fichier (catalyseur2960_template_ttp.txt), mais pour des raisons d'explication, j'en ai créé trois pour chaque paramètre. Il est divisé.

(1) Paramètres globaux

Puisque le modèle lié à l'interface a été créé dans (2) et (3), d'autres paramètres globaux sont définis ici.

part1_template


<group name="global_settings">
hostname {{ hostname }}
enable secret {{ secret }}
username {{ username }} privilege 15 password {{ password }}
ip domain-name {{ hostname }}
ip default-gateway {{ default_gw }}
ntp server {{ ntp_server }}
</group>

Les éléments de réglage sont divisés en groupes par « </ groupe>». Le nom du groupe est «global_settings». En conséquence, lorsque le résultat analysé est sorti au format JSON, le résultat sera affiché dans " global_settings ": {~}. Je pense que c'est pratique si vous souhaitez faciliter la visualisation et la séparation du traitement pour chaque élément de réglage.

De plus, dans le groupe, la partie que vous voulez analyser est spécifiée par {{~}} sous une forme similaire au modèle Jinja2. Le résultat de sortie est le suivant.

part1_output_json


[
    {
        "global_settings": {
            "default_gw": "192.168.100.150",
            "hostname": "hqaccess1",
            "ntp_server": "192.168.100.44",
            "password": "cisco",
            "secret": "test",
            "username": "test"
        }
    }
]

(2) Configuration de l'interface VLAN

J'ai créé le modèle suivant avec le nom de groupe vlan_interfaces.

part2_template


<macro>
def check_port_status(data):
    if "down" in data["port_status"]:
        data["status"] = "x"
    else:
        data["status"] = "o"
    return data
</macro>

<group name="vlan_interfaces" macro="check_port_status" del="port_status">
interface Vlan{{ vlan_num }}
 description {{ vlan_desc | ORPHRASE }}
 ip address {{ ip_address }} {{ subnet }}
 shut{{ port_status | default("up") }}
!{{ _end_ }}
</group>

En plus de (1), nous utilisons quatre fonctions supplémentaires.

  1. Modèle d'expression régulière ORPHRASE Si la description contient un mot, spécifiez le modèle d'expression régulière «WORD». S'il y a plusieurs mots séparés par des espaces, tels que << To hqdist1 Gi0 / 1 >>, vous pouvez spécifier PHRASE pour arriver à la fin de la ligne. Si vous pouvez prendre les deux au cas par cas, spécifiez ʻORPHRASE` comme dans ce cas.

  2. Spécification de la valeur par défaut default () Puisque la commande suivant shutdown est ciblée pour l'analyse, s'il y a une commande shutdown, la valeur de port_status sera down (état bloqué). S'il n'y a pas de commande, la valeur par défaut est ʻup` (état ouvert).

  3. Fonction de groupe macro TTP vous permet de définir des macros à l'aide du code Python. Ici, créez la macro check_port_status, et si la valeur de port_status est down, spécifiez la valeur de la clé nouvellement créée status dans x. Pour ʻup, utilisez ʻo.

  4. Fonctions de groupe del Puisque seul status est requis pour les informations de statut ouvert / bloqué, port_status est supprimé du résultat de sortie.

Le résultat de sortie est le suivant.

part2_output_json


[
    {
        "vlan_interfaces": [
            {
                "status": "x",
                "vlan_num": "1"
            },
            {
                "ip_address": "192.168.100.47",
                "status": "o",
                "subnet": "255.255.255.0",
                "vlan_desc": "<< Server Segment >>",
                "vlan_num": "100"
            }
        ]
    }
]

(3) Réglage de l'interface L2

Enfin, j'ai créé le modèle suivant avec le nom de groupe l2_interfaces.

part3_template


<macro>
def check_port_status(data):
    if "down" in data["port_status"]:
        data["status"] = "x"
    else:
        data["status"] = "o"
    return data

def check_stp_option(data):
    if "portfast" in data["stp_option"]:
        data["portfast"] = "o"
    else:
        data["portfast"] = "x"
    return data
</macro>

<group name="l2_interfaces" exclude="ip_setting, no_ip_setting" macro="check_port_status, check_stp_option" del="port_status, stp_option">
interface {{ port_no }}
 description {{ description | ORPHRASE }}
 switchport access vlan {{ vlan | default("1") }}
 switchport trunk allowed vlan {{ vlan }}
 switchport mode {{ mode | default("access") }}
 duplex {{ duplex | default("auto") }}
 speed {{ speed | default("auto") }}
 shut{{ port_status | default("up") }}
 spanning-tree {{ stp_option | default("none") }}
 ip {{ ip_setting | ORPHRASE }}
 no ip {{ no_ip_setting | ORPHRASE }}
!{{ _end_ }}
</group>

Fondamentalement, c'est une application de (1) et (2), mais pour afficher le résultat dans la table de gestion des ports uniquement vers l'interface L2, les modèles ʻip {{ip_setting}} ʻand` no ip {{no_ip_setting}} ʻ sont utilisés. S'il y a un paramètre IP (= paramètre d'interface L3) qui correspond à cela, utilisez la fonction de groupe exclude. , Le résultat de l'interface correspondante est exclu.

Le résultat de sortie est le suivant.

part3_output_json


[
    {
        "l2_interfaces": [
            {
                "description": "<< To PC1 >>",
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/1",
                "portfast": "o",
                "speed": "auto",
                "status": "o",
                "vlan": "100"
            },
            {
                "description": "<< To PC2 >>",
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/2",
                "portfast": "o",
                "speed": "auto",
                "status": "o",
                "vlan": "100"
            },
            {
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/3",
                "portfast": "o",
                "speed": "auto",
                "status": "x",
                "vlan": "100"
            },
            {
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/4",
                "portfast": "o",
                "speed": "auto",
                "status": "x",
                "vlan": "100"
            },
            {
                "description": "<< To PC3 >>",
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/5",
                "portfast": "o",
                "speed": "auto",
                "status": "o",
                "vlan": "101"
            },
            {
                "description": "<< To PC4 >>",
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/6",
                "portfast": "o",
                "speed": "auto",
                "status": "o",
                "vlan": "101"
            },
            {
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/7",
                "portfast": "o",
                "speed": "auto",
                "status": "x",
                "vlan": "101"
            },
            {
                "duplex": "auto",
                "mode": "access",
                "port_no": "FastEthernet0/8",
                "portfast": "o",
                "speed": "auto",
                "status": "x",
                "vlan": "101"
            },
            {
                "description": "<< To hqdist1 Gi0/1 >>",
                "duplex": "full",
                "mode": "trunk",
                "port_no": "GigabitEthernet0/1",
                "portfast": "x",
                "speed": "1000",
                "status": "o",
                "vlan": "100-101"
            },
            {
                "description": "<< To hqdist2 Gi0/1 >>",
                "duplex": "full",
                "mode": "trunk",
                "port_no": "GigabitEthernet0/2",
                "portfast": "x",
                "speed": "1000",
                "status": "o",
                "vlan": "100-101"
            }
        ]
    }
]

Générer une table de gestion des ports

Le résultat de la conversion du résultat de sortie (3) dans la section précédente au format dictionnaire et de sa sortie au format CSV est le suivant. portlist_output.png

[Tableau de gestion du dernier port](https://qiita.com/tech_kitara/items/b6ffd9790483b08b568b#%E3%83%9D%E3%83%BC%E3%83%88%E7%AE%A1%E7%90 Par rapport à% 86% E8% A1% A8), il existe des différences entre les cellules E10 et E11 en raison de l'ajout de la commande "switchport trunk allowed vlan 100-101" à Gi0 / 1 et Gi0 / 2, mais sinon fondamentalement La même chose a été générée.

finalement

Jusqu'à présent, j'utilisais TextFSM et Genie Parser comme analyseurs pour les appareils NW, mais si vous souhaitez créer votre propre analyseur qui convient à votre environnement, je pense que TTP est également une option puissante en ce qui concerne la fonctionnalité et la personnalisation. L'ensemble de fichiers introduit cette fois a été téléchargé sur GitHub --portlist_generator, donc j'espère que vous le trouverez utile.

Recommended Posts

J'ai essayé de générer automatiquement une table de gestion des ports à partir de L2SW Config
J'ai créé un outil pour générer automatiquement un simple diagramme ER à partir de l'instruction CREATE TABLE
J'ai essayé d'utiliser PI Fu pour générer un modèle 3D d'une personne à partir d'une image
J'ai créé un plugin pour générer une table Markdown à partir de csv avec Vim
J'ai essayé de générer une chaîne de caractères aléatoire
J'ai essayé de générer automatiquement la chaîne de caractères à entrer dans M. Adjustment avec Python
[Python] J'ai essayé de créer automatiquement un rapport quotidien de YWT avec la messagerie Outlook
Je veux démarrer beaucoup de processus à partir de python
Je veux générer automatiquement un nom de groupe de metal moderne
J'ai fait une commande pour générer un commentaire pour une table dans Django
J'ai essayé d'obtenir une base de données sur les courses de chevaux en utilisant Pandas
Un mémorandum lors de l'acquisition automatique avec du sélénium
J'ai essayé de créer une expression régulière de "montant" en utilisant Python
J'ai essayé de créer une expression régulière de "temps" en utilisant Python
J'ai essayé de créer une liste de nombres premiers avec python
J'ai essayé de créer une expression régulière de "date" en utilisant Python
J'ai essayé d'obtenir une liste de noms AMI en utilisant Boto3
J'ai essayé de couper une image fixe de la vidéo
J'ai essayé de collecter automatiquement des images de Kanna Hashimoto avec Python! !!
J'ai essayé de créer un mécanisme de contrôle exclusif avec Go
J'ai essayé de créer un linebot (implémentation)
J'ai essayé de créer un linebot (préparation)
J'ai essayé d'extraire automatiquement les mouvements des joueurs Wiire avec un logiciel
J'ai essayé d'envoyer un e-mail de fin d'inscription depuis Gmail avec django.
[Outlook] J'ai essayé de créer automatiquement un e-mail de rapport quotidien avec Python
J'ai créé une API Web
J'ai essayé d'obtenir automatiquement le RSS de la chanson la plus populaire de l'iTunes Store
J'ai essayé d'effectuer une analyse de cluster de clients à l'aide des données d'achat
J'ai essayé d'afficher la valeur d'altitude du DTM dans un graphique
J'ai essayé de vérifier le résultat du test A / B avec le test du chi carré
J'ai essayé la détection 3D d'une voiture
J'ai essayé d'implémenter le jeu de cartes de Trump en Python
J'ai fait une application d'envoi de courrier simple avec tkinter de Python
[Azure] J'ai essayé de créer une machine virtuelle Linux avec Azure de Microsoft Learn
[IBM Cloud] J'ai essayé d'accéder à la table Db2 on Cloud à partir de Cloud Funtions (python)
J'ai essayé d'extraire le dessin au trait de l'image avec Deep Learning
J'ai créé un outil pour générer du Markdown à partir du fichier JSON Scrapbox exporté
J'ai créé un outil pour sauvegarder automatiquement les métadonnées de l'organisation Salesforce
[Python] J'ai essayé d'obtenir le nom du type sous forme de chaîne de caractères à partir de la fonction type
J'ai essayé de créer un modèle avec l'exemple d'Amazon SageMaker Autopilot
J'ai essayé d'envoyer automatiquement la littérature du nouveau virus corona à LINE avec Python
J'ai essayé de créer une méthode de super résolution / ESPCN
J'ai essayé la fonction de tableau croisé dynamique des pandas
J'ai implémenté DCGAN et essayé de générer des pommes
J'ai essayé d'informer Slack de la mise à jour de Redmine
J'ai essayé de trouver le rapport de circonférence par 100 millions de chiffres
Comment générer un objet Python à partir de JSON
J'ai essayé de créer une méthode de super résolution / SRCNN ③
J'ai essayé de créer une méthode de super résolution / SRCNN ②
J'ai créé un jeu ○ ✕ avec TensorFlow
J'ai essayé de vectoriser les paroles de Hinatazaka 46!
J'ai créé une fonction pour récupérer les données de la colonne de base de données par colonne en utilisant sql avec sqlite3 de python [sqlite3, sql, pandas]
J'ai essayé de faire quelque chose comme un chatbot avec le modèle Seq2Seq de TensorFlow
J'ai essayé de notifier la mise à jour de "Devenir romancier" en utilisant "IFTTT" et "Devenir un romancier API"
Essayez de créer une table d'enregistrement de bataille avec matplotlib à partir des données de "Schedule-kun"