В этом блоге мы собираемся показать, как использовать библиотеку Python draw_network_plot для простого создания топологии сети DrawIO вместо того, чтобы рисовать их вручную.

DrawIO широко используется в качестве бесплатной альтернативы Microsoft Visio для рисования сетевых топологий.

Я буду использовать Netmiko и CDP для получения данных, необходимых для построения графика самих устройств, но эта часть не будет в центре внимания статьи.

Основное внимание в статье уделяется тому, как использовать библиотеку «drawio_network_plot» для создания файла DrawIO.

Убедитесь, что у вас установлен Python 3.7 и выше, затем установите библиотеку, используя:
$ pip install drawio_network_plot

Лабораторная работа выполняется на EVE-NG с использованием образа Cisco 7200VXR для создания топологии, вся топология — L3 с Loopback, поэтому сервер Python CentOS сможет подключаться по ssh к каждому устройству.

Схема топологии EVE-NG (не создана):

Описание изображения

Вы можете найти как приведенный ниже скрипт, так и все конфигурации устройств Cisco EVE-NG по следующей ссылке Github:
drawio_network_plot/examples/cisco_gather_cdp_and_plot

from netmiko import ConnectHandler
import re 
from drawio_network_plot.drawio_network_plot import NetPlot

# ----------------- Getting live CDP Neigbors to gather links endpoints ---------------------------
def retieve_lldp_neigbor_hostname(devices_list):
    list_of_cdp_neighborship = []
    for device in devices_list:
        device_dictionary = {
                            'device_type': 'cisco_ios',  
                            'host': device['ip_address'],
                            'username': 'automation',
                            'password' : '1234567',
                        }
        net_connect = ConnectHandler(**device_dictionary)
        output = net_connect.send_command("show cdp neighbor")
        lines_list = output.splitlines()
        for line in lines_list:
            try:
                # regex to search the name of the device before the domain ID ".default" , then removing the word ".default" from the string
                link = {
                            'sourceNodeID' : device['nodeName'],
                            'destinationNodeID' : re.search('\S+\.default',line).group().replace('.default','') 
                            }
                # checking for duplication before adding new link : 
                if {'sourceNodeID':link['destinationNodeID'],'destinationNodeID':link['sourceNodeID']} not in list_of_cdp_neighborship:
                    list_of_cdp_neighborship.append(link)
            except:
                continue
        net_connect.disconnect()
    return list_of_cdp_neighborship

def main():
    # Lab Devices , must have the device type for the plotting library to work 
    devices = [
            {'nodeName':'Router_1','ip_address':'100.0.1.1','nodeType':'router','nodeDescription':'NA'},
            {'nodeName':'Router_2','ip_address':'100.0.1.2','nodeType':'router','nodeDescription':'NA'},
            {'nodeName':'Spine_1','ip_address':'100.0.2.1','nodeType':'l3_switch','nodeDescription':'NA'},
            {'nodeName':'Spine_2','ip_address':'100.0.2.2','nodeType':'l3_switch','nodeDescription':'NA'},
            {'nodeName':'Leaf_1','ip_address':'100.0.3.1','nodeType':'l2_switch','nodeDescription':'NA'},
            {'nodeName':'Leaf_2','ip_address':'100.0.3.2','nodeType':'l2_switch','nodeDescription':'NA'},
            {'nodeName':'Leaf_3','ip_address':'100.0.3.3','nodeType':'l2_switch','nodeDescription':'NA'}
            ]
    # Getting list of links for each device
    list_of_cdp_neighborship = retieve_lldp_neigbor_hostname(devices)
    for peering in list_of_cdp_neighborship:
        print(peering)

    # ------------------------------------------------------------------------------------------------------
    # ------------------------------------------------------------------------------------------------------
    # ----------------- Main Part : using library to generate XML DrawIIO format ---------------------------
    # Using the Plot library 
    x = NetPlot()
    x.addNodeList(devices)
    x.addLinkList(list_of_cdp_neighborship)
    print(x.display_xml())
    # ------------------------------------------------------------------------------------------------------
    # ------------------------------------------------------------------------------------------------------
    # ------------------------------------------------------------------------------------------------------

if __name__ == "__main__":
    main()
Войти в полноэкранный режим

Выйти из полноэкранного режима

Помните, что вы можете собирать данные, как хотите, это была просто демонстрация того, что вы можете сделать, основной код, который нужно запомнить, это часть построения графика:

# please adhere to the naming scheme in the variables 
device_list = [{'nodeName' : 'TOR_1','nodeType' : 'l2_switch','nodeDescription' : 'Leaf Switch 01'}]
x = NetPlot()
# **IMPORTANT NOTE :**---> Make sure that the sourceNode in the connection is the higher level device and that connections are not replicated , this way when you use the DrawIO automatic layout , it would create the diagram hierarchy the correct way 
connections_list = [{'sourceNodeID' : 'Router_1','destinationNodeID' : 'Core_switch_1'}]
    # Adding using list all at once
    x.addNodeList(device_list)
    x.addLinkList(connections_list)
    # Adding node by node and link by link
    x.addNode(nodeName='Router_18',nodeType='router')
    x.addLink('Router_17','Router_18')

    # --- Output ---
    # You can print the XML to the Stdout 
    print(x.display_xml())
    # Or You can also directly generate an XML file using the built in function :
    # x.exportXML('examples/output.xml')    
Войти в полноэкранный режим

Выйти из полноэкранного режима

Сгенерированный вывод будет свернут в одну точку, вам нужно будет выбрать макет, который вы хотите в DrawIO, после открытия файла, как показано ниже:


Сгенерированная топология

1- Откройте сгенерированный файл XML в DrawIO
Исходный сгенерированный файл

2- перейдите в меню «Упорядочить/Макет/Вертикальное дерево».
перейдите в «Упорядочить/Макет/Вертикальное дерево»

3- Окончательный результат
Описание изображения

Для любого комментария к пакету pip , добавлению функции или любому комментарию , пожалуйста , поделитесь своими предложениями , так как это моя первая библиотека PIP , и божественно она не идеальна .

Спасибо …