Python для сетевых инженеров: Python для сетевых инженеров — Документация Python для сетевых инженеров 3.0

Содержание

Python для сетевых инженеров: начало пути / Хабр

Наверное, многие сетевые инженеры уже поняли, что администрирование сетевого оборудования только через CLI слишком трудоёмко и непродуктивно. Особенно когда под управлением находятся десятки или сотни устройств, часто настроенных по единому шаблону. Удалить локального пользователя со всех устройств, проверить конфигурации всех маршрутизаторов на соответствие каким-то правилам, посчитать количество включенных портов на всех коммутаторах — вот примеры типовых задач, решать которые без автоматизации нецелесообразно.

Эта статья в основном для сетевых инженеров, которые пока не знакомы или очень слабо знакомы с Python. Мы рассмотрим пример скрипта для решения некоторых практических задач, который вы сразу сможете применять в своей работе.


Для начала расскажу, почему я выбрал Python.

Во-первых, это легкий в освоении язык программирования, который позволяет решать очень широкий круг задач.

Во-вторых, крупные производители сетевого оборудования, такие как Cisco, Juniper, Huawei, внедряют поддержку Python на своем оборудовании.

У языка есть будущее в сетевой сфере, и его изучение не будет пустой тратой времени.

В-третьих, язык очень распространен. Для него написано много полезных библиотек, есть большое сообщество программистов, и найти ответы на большинство вопросов в интернете можно в первых строках поисковой выдачи.

Я занимаюсь проектированием и немного внедрением сетевых проектов. В одном из них потребовалось решить сразу две задачи.

  1. Пройтись по нескольким сотням филиальных маршрутизаторов и убедиться, что они настроены единообразно. Например, что для связи с ЦОД используется интерфейс Tunnel1, а не Tunnel0 или Tunnel99. И что эти интерфейсы настроены одинаково, за исключением их IP-адресов, естественно.
  2. Перенастроить все маршрутизаторы, в том числе добавить статический маршрут через IP-адрес местного провайдера. То есть эта команда будет уникальной для каждого маршрутизатора.

На помощь пришел скрипт на Python. Его разработка и тестирование заняли один день.

Первое, что нужно сделать, это установить Python и крайне желательно PyCharm CE. Скачиваем и устанавливаем Python 3 (сейчас последняя версия 3.6.2). При установке выбираем «Customize installation» и на этапе «Advanced Options» устанавливаем галку напротив «Add Python to environment variables».

PyCharm CE — это бесплатная среда разработки с очень удобным отладчиком. Скачиваем и устанавливаем.

Второй шаг — устанавливаем необходимую библиотеку netmiko. Она нужна для взаимодействия с устройствами по SSH или telnet. Библиотеку устанавливаем из командной строки:

pip install netmiko

Третьим шагом будет подготовка исходных данных и скрипта под наши задачи.

В качестве входных данных будем использовать текстовый файл “ip.txt”. В каждой строчке файла должен быть IP-адрес устройства, к которому мы подключаемся. Через запятую можно указать логин и пароль для конкретного устройства. Если этого не сделать, то будут использоваться те, которые вы введёте при запуске скрипта.

Пробелы будут проигнорированы. Если первый символ в строке «#», то она считается комментарием и игнорируется. Вот пример корректного файла:

Сам скрипт логически состоит из двух частей: основной программы и функции doRouter(). Внутри неё выполняется подключение к маршрутизатору, отправка команд в CLI, получение и анализ ответов. Входными данными для функции являются: IP-адрес маршрутизатора, логин и пароль. При возникновении проблем функция вернёт IP-адрес маршрутизатора, мы его запишем в отдельный файл fail.txt. Если всё прошло хорошо, то будет просто выведено сообщение на экран.

Почему нужно выносить взаимодействие с маршрутизаторами в отдельную функцию, а не выполнить всё в цикле в основной программе? Главная причина — продолжительность работы скрипта. Подключение поочередно ко всем маршрутизаторам заняло у меня 4 часа. В основном из-за того, что какие-то из них не отвечали и скрипт долго ждал истечения таймаута. Поэтому запускать мы будем параллельно по 10 экземпляров функций.

В моём случае это сократило время выполнения скрипта до 10 минут.

Рассмотрим теперь подробнее основную программу.

Ради безопасности не будем хранить логин и пароль в скрипте. Поэтому выведим на экран приглашение для их ввода. Причем при вводе пароля он не будет отображаться. Эти глобальные переменные используем в процедуре doRouter. У меня были проблемы с работой getpass в PyCharm под Windows. Скрипт работал корректно, только если выполнять его в режиме Debug, а не Run. В командной строке всё работало без нареканий. Также скрипт тестировался в OS X, там проблем в PyCharm замечено не было.

user_name = input("Enter Username: ")
pass_word = getpass()

Потом читаем файл с IP-адресами. Конструкция

try…except

позволит корректно обработать ошибку чтения файла. На выходе получим массив данных для подключения

connection_data

, содержащий IP-адрес, логин и пароль.

try:
    f = open('ip.txt')
    connection_data=[]
    filelines = f. read().splitlines()
    for line in filelines:
if line == "": continue
        if line[0] == "#": continue
        conn_data = line.split(',')
        ipaddr=conn_data[0].strip()
        username=global_username
        password=global_password
        if len(conn_data) > 1 and conn_data[1].strip() != "": username = conn_data[1].strip()
        if len(conn_data) > 2 and conn_data[2].strip() != "": password = conn_data[2].strip()
        connection_data.append((ipaddr, username, password))
    f.close()
except:
    sys.exit("Couldn't open or read file ip.txt")

Далее создаём список процессов и запускаем их. Метод создания процессов я задал как “spawn”, чтобы в Windows и OS X скрипт работал одинаково. Количество созданных процессов будет равно количеству IP-адресов. Но выполняться одновременно будут не более 10. В список

routers_with_issues

записываем то, что вернут функции

doRouter

. В нашем случае это IP-адреса маршрутизаторов, с которыми были проблемы.

multiprocessing.set_start_method("spawn")
with multiprocessing.Pool(maxtasksperchild=10) as process_pool:
    routers_with_issues = process_pool.map(doRouter, connection_data, 1)
    process_pool.close()
    process_pool.join()

Команда

process_pool.join()

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

doRouter()

и только потом продолжил выполнять основную программу.

В конце создаем/переписываем текстовый файл, в котором у нас будут IP-адреса ненастроенных маршрутизаторов. Также выводим этот список на экран.

failed_file = open('fail.txt', 'w')
for item in routers_with_issues:
    if item != None:
      failed_file.write("%s\n" % item)
      print(item)

Теперь разберем процедуру

doRouter()

. Первое, что нужно сделать, — обработать входные данные. С помощью ReGex проверяем, что функции был передан корректный IP-адрес.

ip_check = re. (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", ip_address)
if ip_check == []:
    print(bcolors.FAIL + "Invalid IP - " + str(ip_address) + bcolors.ENDC)
    return ip_address

Далее создаём словарь с необходимыми для подключения данными и подключаемся к маршрутизатору.

device = {
    'device_type': 'cisco_ios',
    'ip': ip_address.strip(),
    'username': username,
    'password': password,
    'port': 22, }
try:
    config_ok = True

    net_connect = ConnectHandler(**device)

Отправляем команды и анализируем полученный ответ от маршрутизатора. Он будет помещён в переменную

cli_response

. В этом примере мы проверяем текущие настройки. Результат выводим на экран. Данную часть нужно менять под разные задачи. В этом скрипте проверяем текущую конфигурацию маршрутизатора. Если она корректная, то вносим изменения. Если при проверке обнаружены проблемы, то присваиваем переменной

config_ok

значение

False

и не применяем изменения.

cli_response = net_connect.send_command("sh dmvpn | i Interface")
cli_response = cli_response.replace("Interface: ", "")
cli_response = cli_response.replace(", IPv4 NHRP Details", "").strip()
if cli_response != "Tunnel1":
    print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - DMVPN not on Tunnel1.  " + cli_response+ " " + bcolors.ENDC)
    config_ok=False

Тут будут полезны следующие операции работы со строками.

Операция Описание Пример
+ Объединение строк s3 = s1 + s2
>>> print(‘Happy New ‘ + str(2017) + ‘ Year’)
Happy New 2017 Year
len(s) Определение длины строки
[] Выделение подстроки (индекс начинается с нуля) s[5] — шестой символ
s[5:7] — символы с шестого по восьмой
s[-1] — последний символ, то же, что s[len(s)-1]
s. split()
s.join()
Разделить строки
Объединить строки
>>> ‘Петя, Лёша, Коля’.split(‘,’)
[‘Петя’, ‘Лёша’, ‘Коля’]

>>> ‘,’.join({‘Петя’, ‘Лёша’, ‘Коля’})
‘Лёша, Петя, Коля’

str(L)
list(s)
Преобразовать список в строку
Преобразовать строку в список
>>> str([‘1’, ‘2’, ‘3’])
«[‘1’, ‘2’, ‘3’]»

>>> list(‘Test’)
[‘T’, ‘e’, ‘s’, ‘t’]

% Форматирование по шаблону >>> s1, s2 = ‘Митя’, ‘Василиса’
>>> ‘%s + %s = любовь’ % (s1, s2)
‘Митя + Василиса = любовь’
f Подстановка переменных >>> a=’Максим’
>>> f’Имя {a}’
‘Имя Максим’
str.find(substr) Поиск подстроки substr в строке str
Возвращает позицию первой найденной подстроки
>>> ‘This is a text’. find(‘a’)
8
str.replace(old, new) Замена подстроки old на подстроку new в строке str >>> newstr = ‘This is a text’.replace(‘ is ‘, ‘ is not ‘)
>>> print(newstr)
This is not a text
str.strip()
str.rstrip()
Удалить пробелы и табуляции в начале и конце (или только в конце) >>> ‘ This is a text \t\t\t’.strip()
‘This is a text’

Чтобы решить задачу по добавлению статического маршрута, для начала нужно определить IP-адрес

next-hop

. В моем случае самый простой способ — посмотреть адрес

next-hop

у существующих статических маршрутов.

cli_response2=net_connect.send_command("sh run | i ip route 8.8.8.8 255.255.255.255")
if cli_response2.strip() == "":
    print(str(ip_address)+" — " + bcolors.FAIL + "WARNING — couldn't find static route to 8. 8.8.8" + bcolors.ENDC)
    config_ok=False

ip_next_hop = ""
if cli_response2 != "":
    ip_next_hop = cli_response2.split(" ")[4]

if ip_next_hop == "":
    print(str(ip_address)+" — " + bcolors.FAIL + "WARNING — couldn't find next-hop IP address " + bcolors.ENDC)
    config_ok=False

Можно отправлять одну или несколько конфигурационных команд сразу. У меня плохо работала отправка больше 5 команд одновременно, при необходимости можно просто повторить конструкцию несколько раз.

config_commands = ['ip route 1.1.1.1 255.255.255.255 '+ip_next_hop,
                   'ip route 2.2.2.2 255.255.255.255 '+ip_next_hop]
net_connect.send_config_set(config_commands)
Полный скрипт.
import sys
from netmiko import ConnectHandler
from getpass import getpass
import time
import multiprocessing
import re

start_time = time.time()

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

def doRouter(connection_data):

    ip_address = connection_data[0]
    username = connection_data[1]
    password = connection_data[2]

    ip_check = re. (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$", ip_address)
    if ip_check == []:
        print(bcolors.FAIL + "Invalid IP - " + str(ip_address) + bcolors.ENDC)
        return ip_address

    device = {
        'device_type': 'cisco_ios',
        'ip': ip_address.strip(),
        'username': username,
        'password': password,
        'port': 22, }
    try:
        config_ok = True

        net_connect = ConnectHandler(**device)

        cli_response = net_connect.send_command("sh dmvpn | i Interface")
        cli_response = cli_response.replace("Interface: ", "")
        cli_response = cli_response.replace(", IPv4 NHRP Details", "").strip()
        if cli_response != "Tunnel1":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - DMVPN not on Tunnel1.  " + cli_response+ " " + bcolors.ENDC)
            config_ok=False

        cli_response2=net_connect.send_command("sh run | i ip route 1.1.1.1 255.255.255. 255")
        if cli_response2.strip() == "":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - couldn't find static route to 8.8.8.8" + bcolors.ENDC)
            config_ok=False

        ip_next_hop = ""
        if cli_response2 != "":
            ip_next_hop = cli_response2.split(" ")[4]

        if ip_next_hop == "":
            print(str(ip_address)+" - " + bcolors.WARNING + "WARNING - couldn't find next-hop IP address " + bcolors.ENDC)
            config_ok=False


        if config_ok:
            config_commands = ['ip route 1.1.1.1 255.255.255.255 '+ip_next_hop,
                               'ip route 2.2.2.2 255.255.255.255 '+ip_next_hop]
         	    net_connect.send_config_set(config_commands)
            print(str(ip_address) + " - " + "Static routes added")
        else:
            print(str(ip_address) + " - " + bcolors.FAIL + "Routes weren't added because config is incorrect" + bcolors.ENDC)
            return ip_address

        if config_ok:
   	                  net_connect. send_command_expect('write memory')
            print(str(ip_address) + " - " + "Config saved")

        net_connect.disconnect()
    except:
        print(str(ip_address)+" - "+bcolors.FAIL+"Cannot connect to this device."+bcolors.ENDC)
        return ip_address
    print(str(ip_address) + " - " + bcolors.OKGREEN + "Router configured sucessfully" + bcolors.ENDC)


if __name__ == '__main__':

    # Enter valid username and password. Note password is blanked out using the getpass library
    global_username = input("Enter Username: ")
    global_password = getpass()

    try:
        f = open('ip.txt')
        connection_data=[]
        filelines = f.read().splitlines()
        for line in filelines:
            if line == "": continue
            if line[0] == "#": continue
            conn_data = line.split(',')
            ipaddr=conn_data[0].strip()
            username=global_username
            password=global_password
            if len(conn_data) > 1 and conn_data[1].strip() != "": username = conn_data[1]. strip()
            if len(conn_data) > 2 and conn_data[2].strip() != "": password = conn_data[2].strip()
            connection_data.append((ipaddr, username, password))
        f.close()
    except:
        sys.exit("Couldn't open or read file ip.txt")

    multiprocessing.set_start_method("spawn")
    with multiprocessing.Pool(maxtasksperchild=10) as process_pool:
        routers_with_issues = process_pool.map(doRouter, connection_data, 1)  # doRouter - function, iplist - argument
        process_pool.close()
        process_pool.join()

    print("\n")
    print("#These routers weren't configured#")

    failed_file = open('fail.txt', 'w')
    for item in routers_with_issues:
        if item != None:
          failed_file.write("%s\n" % item)
          print(item)

    #Completing the script and print running time
    print("\n")
    print("#This script has now completed#")
    print("\n")
    print("--- %s seconds ---" % (time.time() - start_time))

После подготовки скрипта выполнить его можно из командной строки или из PyCharm CE. Из командной строки запускаем командой:

python script.py

Я рекомендую пользоваться PyCharm CE. Там создаём новый проект, файл Python (File → New…) и вставляем в него наш скрипт. В папку со скриптом кладем файл ip.txt и запускаем скрипт (Run → Run)

Получаем следующий результат:

bash ~/PycharmProjects/p4ne $ python3 script.py 
Enter Username: cisco
Password: 
Invalid IP - 10.1.1.256
127.0.0.1 - Cannot connect to this device.
1.1.1.1 - Cannot connect to this device.
10.10.100.227 - Static routes added
10.10.100.227 - Config saved
10.10.100.227 - Router configured sucessfully
10.10.31.170 - WARNING - couldn't find static route to 8.8.8.8
10.10.31.170 - WARNING - couldn't find next-hop IP address 
10.10.31.170 - Routes weren't added because config is incorrect
2.2.2.2 - Cannot connect to this device.


#These routers weren't configured#
10.1.1.256
127.0.0.1
217.112.31.170
1.1.1.1
2.2.2.2


#This script has now completed#

Пару слов о том, как отладить скрипт. Легче всего это делать в PyCharm. Отмечаем строчку, на которой хотим остановить выполнение скрипта, и запускаем выполнение в режиме отладки. После того, как скрипт остановится, можно будет посмотреть текущие значения всех переменных. Проверить, что передаются и принимаются корректные данные. Кнопками «Step Into» или «Step Into My Code» можно пошагово продолжить выполнение скрипта.

Ограничения описанной версии скрипта:

Этот скрипт был написан для решения конкретных задач. Однако он универсален и, надеюсь, поможет ещё кому-нибудь в работе. А самое главное — послужит первым шагом в освоении Python.

При написании скрипта использовались следующие ресурсы:


Александр Гаршин, ведущий инженер-проектировщик систем передачи данных компании «Инфосистемы Джет»

Курс Основы программирования на Python для сетевых инженеров в Екатеринбурге

Данный курс предназначен для желающих начать осваивать язык программирования Python (как с опытом работы с другими языками программирования, так и без него) для дальнейшего применения в различных направлениях.

К освоению программы допускаются лица, уверенно владеющие приемами работы на компьютере: управлением файловой системой, установкой ПО и конфигурацией сетевых параметров. Для успешного прохождения обучения желательно иметь опыт программирования на любом языке.

Содержание курса

Модуль 1. Введение в Python. Настройка среды разработки

Введение в Python
Настройка среды разработки

Модуль 2. Типы данных, переменные, операторы

Типы данных и манипуляции с ними
Операторы языка

Модуль З. Функции и модули

Скачивание и использование стандартных модулей
Модуляризация собственных приложений

Модуль 4. Решение типовых алгоритмических задач

Типовые алгоритмические задачи
Применение языка Python для реализации алгоритмов

Модуль 5. Элементы объектно-ориентированного программирования

Основы ООП
Классы и методы в Python

Модуль 6. Взаимодействие с приложениями и устройствами

Понятие API, протокол форматов сериализации
Взаимодействие с системами, реализующими REST API
Взаимодействие с системами и устройствами, реализующими другие протоколы

Модуль 7. Параллельное выполнение

Понятие и проблемы асинхронного выполнения кода
Средства создания асинхронного кода в Python

Модуль 8. Автоматизация. Решение задач, имеющих отношение к практике

Обзор типовых задач автоматизации
Решение типовых задач автоматизации средствами Python
Обзор типовых задач конфигурации сети
Решение типовых задач конфигурации сети средствами Python

Python 3 для сетевых инженеров — Программирование — Учебники

Python 3 для сетевых инженеров

Автор — Наташа Самойленко

Если «в двух словах», то книга «Python 3 для сетевых инженеров» Наташи Самойленко — это такой CCNA по Python. С одной стороны, книга достаточно базовая, чтобы её мог одолеть любой желающий, а с другой стороны, в книге рассматриваются все основные темы, которые позволят дальше расти самостоятельно. Книга не ставит своей целью глубокое рассмотрение Python. Задача книги – объяснить понятным языком основы Python и дать понимание необходимых инструментов для его практического использования. Всё, что рассматривается в книге, ориентировано на сетевое оборудование и работу с ним. Это даёт возможность сразу использовать в работе сетевого инженера то, что было изучено на курсе. Все примеры показываются на примере оборудования Cisco, но, конечно же, они применимы и для любого другого оборудования.

Книга разделена на шесть частей. Первая часть книги посвящена основам языка, которые являются фундаментом для дальнейшего его изучения. Вторая часть описывает различные техники повторного использования кода: функции, модули, итераторы и генераторы. Третья часть знакомит Вас с регулярными выражениями. В ней рассматривается и синтаксис регулярных выражений, и как с ними работать в Python. После этой главы Вы с лёгкостью сможете получать нужную информацию из вывода команд. Четвёртая часть содержит необходимую информацию про запись и передачу данных средствами Python. Пятая часть рассказывает про работу с сетевым оборудованием через Python. Шестая часть посвящена основам работы с Ansible, а также модулям для работы с оборудованием Cisco. Этой информации будет достаточно, чтобы начать использовать Ansible. В приложениях собраны те темы, которые не вошли в другие разделы, но которые всё равно очень полезны.

Данная книга предназначена главным образом для сетевых инженеров с опытом программирования и без. Все примеры и домашние задания будут построены с уклоном на сетевое оборудование. Эта книга будет полезна сетевым инженерам, которые хотят автоматизировать задачи, с которыми сталкиваются каждый день и хотели заняться программированием, но не знали, с какой стороны подойти.

Издательство – Самиздат

Год издания – 2017

Формат книги — PDF

Размер — 11,8 Мб

СКАЧАТЬ с gigapeta.com

Или

СКАЧАТЬ с turbobit.net

Или

СКАЧАТЬ с hitfile.net

Программирование для сетевых инженеров: работа с конфигурацией — SENETSY

Даже в хорошей, с точки зрения дизайна, сети время от времени приходится проводить работы по актуализации конфигураций тех или иных сущностей. Среди наиболее веских и ожидаемых причин подобной активности можно отметить миграции для согласования физической и логической плоскостей, развитие сети в рамках процесса технологической эволюции, гармонизация архитектур присоединяемых сегментов и решение проблем роста. На самом деле, жизненный цикл сети, почти всегда представляет из себя изменения с тем или иным уровнем рисков и панируемого влияния на сервис, в оценке которого нельзя не учитывать человеческий фактор. Хотя, будет вполне уместным обобщить это описание на большинство областей человеческой деятельности, функционирование коммуникационных сетей обладает некоторыми особенностями, которые заслуживают понимания, или хотя бы внимания, — элементы коммуникационных сетей находятся в плотной связи, тесно взаимодействуют и оказывают не только прямое, но и косвенное воздействие друг на друга. Поэтому, грамотная стратегия проводимых работ станет только продуктивнее будучи подкреплённой механизмами, которые снижают, насколько это возможно, вероятность появления человеческих ошибок. В очередной статье цикла «Зачем сетевым инженерам программирование» расскажу о вариантах применения автоматизации в одной задаче подобного рода.

Во многих «букварях» по сетевой архитектуре термины large-scale networks и hierarchical networks используются почти как синонимы, применительно к дизайну IGP домена обозначен простой и, на первый взгляд, понятный дизайн — дробление домена на области. При этом, порог насыщения — вещь сугубо индивидуальная, в каких-то случаях в одной IGP области может нормально сосуществовать тысяча современных маршрутизаторов, в ином случае и трехсот достаточно чтобы существенно снизить эксплуатационные характеристики. По большей части этот порог определяется наложенными на IGP протоколами, поэтому в условиях некоторой вариативности и неопределенности границ и масштабов будущей сети, «зубры» индустрии находят более гибким путь построения плоского домена с последующей миграцией его сформировавшихся частей в отдельные области. Иными словами, если вы не можете «сегодня смотреть в завтрашний день», стройте плоскую сеть и дробите ее по факту появления первых признаков деградации времени сходимости или излишней сложности эксплуатации, потому-как отсутствие иерархии все-таки лучше, чем неправильно выбранная в условиях неопределенности структура [1, 2, 3].

Довольно общих описаний и абстрактных примеров, предположим, что мы имеем дело с разросшейся областью OSPFv2 домена, топология физических волокон/каналов которого уже позволяет разглядеть в аморфной структуре границы будущих областей. Я не сторонник менять что-то по принципу «все или ничего», может так случится, что из-за непредвиденных обстоятельств пространство возможностей станет слишком узким, а ожидаемые риски слишком большими. Смена OSPFv2 области является деструктивной операцией, поэтому самая прямолинейная схема процесса миграции, которая заключается в последовательном переводе маршрутизаторов в новую область по пути от будущей границе вниз, удобна далеко во всех топологиях. К счастью, некоторое время назад в рекомендациях к развитию OSPF была обозначена возможность построения связности в рамках нескольких областей [4]. Пользуясь этой возможностью, мы можем разбить миграцию на три этапа:

  1. Построение дополнительной (secondary) связности в рамках новой области
  2. Перевод новой области в основной режим, а старой в дополнительный
  3. Удаление связности в рамках старой области

На первом этапе топология новой области постепенно расширяется, на втором, топология старой области сужается. При соблюдении конгруэнтности топологий старой и новой областей, мы получим согласованную маршрутизацию между переведенными и не переведенными узлами, а это, в свою очередь, делает возможным деление этапов на независимые под-этапы, на каждом из которых работа может производится с некоторой частью узлов. К выбору узлов для работ в рамках под-этапа целесообразно подходить с точки зрения фактической утилизации каналов в конкретной сети, таким образом, чтобы не допускать перезагрузку на границе старой и новой областей. Несмотря на то, что статья посвящена программированию, думаю, не будет лишним сказать пару слов о поведении наложенных на IGP протоколов в контексте смены областей. LDP ведет себя довольно предсказуемо, плавность перевода достигается обеспечением IP связности между transport-address таргетированных и интерфейсных сессий. В силу того, что BGP очень гибкий протокол, стоит обратить пристальное внимание на эту плоскость. Хорошо, если на переводимых узлах BGP не привносит в выбор пути особенных вольностей в виде несогласованного между узлами изменения Local Preferences или других критериев, обуславливающих локальный routing decision. Иными словами, поведение BGP тоже является предсказуемым, в том случае если внутри области выбор маршрута не противоречил правилу follow IGP path. Есть тонкий момент, связанный с работой RSVP в период времени сосуществования двух областей. Почву для размышлений подбрасывает факт наполнения TED таблицы из двух источников с разной видимостью, например, вы вполне можете лишится механизмов FRR до полного окончания работ. Это может случится если маршрутизаторы с большей видимостью, которые находятся в двух областях, посчитают ERO через маршрутизатор с меньшей видимостью, т.е. через переведенный сегмент сети без топологической информации о другой области. Подобное нельзя назвать катастрофой, так как путь в итоге конечно будет установлен, но и забывать об этом не стоит. Особенного искусства требует совмещение работ по внедрению иерархий IGP с работами такого же рода в BGP плоскости, например, миграцией full-mesh в отражатели маршрутов. Внедрение иерархий в разных плоскостях лучше проводить последовательно, то же самое, по моему мнению, относится ко всем вещам, которые прячут маршрутную информацию, суммаризацию проще построить на стабильном фундаменте иерархического IGP, нежели совмещать эти этапы.

Итак, общий план у нас есть, и, если вы еще не передумали, давайте поразмыслим над программной реализацией на Pyez, примерно такой как на этом рисунке.

Каждый красивый овал, может представлять из себя отдельную программную сущность, т.е. такую вещь, которая выполняет работу и готовит данные для следующего этапа. Под исходными данными подразумевается информация из сети, например, чтобы подготовить конфигурацию новой OSPF области, необходимо получить имена активных интерфейсов, принадлежащей старой области, и их веса, а значит нам пригодятся умения работы с Operation таблицами и представлениями. С этими понятиями можно познакомится в предыдущей статье цикла «Программирование для сетевых инженеров: первый кейс». На первом этапе генератор сохраняет в файлы команды необходимые для активации новой области, на втором — для удаления старой и перевода новой в основной режим, на третьем — команды по удалению старой области. Забегая вперед скажу, что для данной статьи я намеренно не пользуюсь визуализаторами шаблонов, наподобие Jinja2. Чтобы не отвлекаться от целевой темы код написан максимально просто. Если вот кому-то интересно документация по ссылке «Jinja2 Documentation».

Код генерации конфигураций этапов

import sys
import yaml
from jnpr.junos.factory.factory_loader import FactoryLoader
from jnpr.junos import Device

def getConnection(p_host, p_user):
           acc = {‘lab’: ‘lab123’}

           try:
                      print ‘             DEBUG — getting ssh connection to ‘ + p_host

                      l_dev = Device(host=p_host, user=p_user, password=acc[p_user] auto_probe=2,
gather_facts=True, port=22)
                      l_dev.open()
                      if (l_dev.connected):
                                   l_dev.timeout = 900
                                   print ‘             DEBUG — ssh cionnection to host ‘ + p_host +
‘ established’
                                   print ‘             DEBUG — connection ‘ + p_host + ‘ named ‘ +
l_dev.facts[‘hostname’] + ‘ established ‘
                                   return l_dev
                      else:
                                   raise Exception(‘ DEBUG — ssh connection to ‘
+ p_host + ‘ was not established’)
           except Exception as ex:
                                   print ‘             DEBUG — ERROR — getConnection : connection to ‘ +
p_host + ‘ was not established. ex:’ + str(ex)
                                   return

def close_dev(d):
           try:
                                   d.close()
           except Exception as ex:
                                   print ‘             DEBUG — ERROR — close_dev : connection to cant be
closed. ex:’ + str(ex)

yml = »’

OSPFInterface:
    rpc: get-ospf-interface-information

    args:
      area: ‘0.0.0.200’
      detail: True
    item: ospf-interface
    view: OSPFInterfaceView

OSPFInterfaceView:
    fields:
      name: interface-name
      type: interface-type
      cost: interface-cost
»’

globals().upd ate(FactoryLoader().load(yaml.load(yml)))

node_list = [‘10.83.20.68’, ‘10.83.20.69’, ‘10.83.20.70’, ‘10.83.20.71’]
abr_list = [‘10.83.20.66’, ‘10.83.20.67’]

for node in node_list + abr_list:
      ddev = getConnection(node, ‘lab’)
      ospf_interfaces = OSPFInterface(ddev).get()

         with open(‘st2-‘ + node + ‘.txt’, «w») as f_st1:
                    f_st1.write(‘delete protocols ospf area 0.0.0.200’ + ‘\n’)
                    f_st1.write(‘delete protocols ospf area 0.0.0.250’ + ‘\n’)
                    for ospf_interface in ospf_interfaces:
                        f_st1.write(‘set protocols ospf area 0.0.0.250 interface ‘ + ospf_interfa
ce.name + ‘ interface-type p2p’ + ‘\n’)
                        f_st1.write(‘set protocols ospf area 0.0.0.200 interface ‘ + ospf_interfa
ce.name + ‘ secondary’ + ‘\n’)
                        f_st1.write(‘set protocols ospf area 0.0.0.200 interface ‘ + ospf_interfa
ce.name + ‘ interface-type p2p’ + ‘\n’)
                        if (ospf_interface.cost != ‘0’):
                               f_st1.write(‘set protocols ospf area 0.0.0.250 interface ‘ + ospf_int
erface.name + ‘ metric ‘ + ospf_interface.cost + ‘\n’)
                               f_st1.write(‘set protocols ospf area 0.0.0.200 interface ‘ + ospf_int
erface.name + ‘ metric ‘ + ospf_interface.cost + ‘\n’)

         with open(‘st3-‘ + node + ‘.txt’, «w») as f_st1:
                    f_st1.write(‘delete protocols ospf area 0.0.0.200’ + ‘\n’)

Для наглядности я собрал в вот такую сеть на vMX.

vMX это полноценный программный маршрутизатор от Juniper Networks, во многом повторяющий поведение своего старшего, железного брата MX. Не то чтобы это был продукт, который нуждается в представлении, просто такие вещи полезно держать под рукой для упражнений в программировании или лабораторных испытаний. Триал, можно скачать тут «vMX Trial Download» инструкцию по установке по этой ссылке «Preparing the System to Install vMX».

Маршрутизаторы bb, abr1 и abr2 образуют нулевую область, маршрутизаторы r1, r2, r3 и r4 — должны быть перемещены из 200-й области в 250-ю.

[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.70;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.0 {
                     interface lo0.0 {
                                 passive;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/2.0 {
                                 interface-type p2p;
                     }
           }
}

[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.66;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.70;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.0 {
                     interface lo0.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/0.0 {
                                 interface-type p2p;
                     }
           }
           area 0.0.0.200 {
                     interface ge-0/0/1.0 {
                                 interface-type p2p;
                     }
           }
}


[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.67;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.70;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.0 {
                     interface lo0.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/0.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/2.0 {
                                 interface-type p2p;
                     }
           }
           area 0.0.0.200 {
                     interface ge-0/0/1.0 {
                                 interface-type p2p;
                     }
           }
}

[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.68;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.70;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.200 {
                     interface ge-0/0/1.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/2.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     interface lo0.0 {
                                 interface-type p2p;
                     }
           }
}


[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.69;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.70;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.200 {
                     interface ge-0/0/0.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     nterface lo0.0 {
                                 interface-type p2p;
                     }
           }
}


[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.70;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.71;
           }
}
ospf {
           area 0.0.0.200 {
                     interface ge-0/0/0.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     nterface lo0.0 {
                                 interface-type p2p;
                     }
           }
}


[email protected]> show configuration protocols

bgp {
           group int {
                     type internal;
                     local-address 10.0.0.71;
                     neighbor 10.0.0.65;
                     neighbor 10.0.0.66;
                     neighbor 10.0.0.67;
                     neighbor 10.0.0.68;
                     neighbor 10.0.0.69;
                     neighbor 10.0.0.70;
           }
}
ospf {
           area 0.0.0.200 {
                     interface ge-0/0/1.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/2.0 {
                                 interface-type p2p;
                     }
                     interface ge-0/0/3.0 {
                                 interface-type p2p;
                     }
                     nterface lo0.0 {
                                 interface-type p2p;
                     }
           }
}


Применительно к маршрутизатору r2, будет сгенерирован следующий набор команд.

Для первого этапа

set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 secondary
set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 secondary
set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 metric 1
set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 secondary
set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1


Для второго этапа

delete protocols ospf area 0.0.0.200
delete protocols ospf area 0.0.0.250
set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 secondary
set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 metric 1
set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 interface-type p2p
set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 secondary
set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 metric 1
set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 metric 1
set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 secondary
set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 interface-type p2p
set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1
set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 metric 1
set protocols ospf area 0.0.0.250 interface lo0.0 interface-type p2p
set protocols ospf area 0.0.0.200 interface lo0.0 secondary
set protocols ospf area 0.0.0.200 interface lo0.0 interface-type p2p


Для третьего этапа

delete protocols ospf area 0.0.0.200

Как я уже писал элементы сети обладают внутренним состоянием, вокруг и внутри них что-то постоянно происходит независимо от того хотим мы этого или нет. Появление таких событий как отказ трансивера, отключение питания на узле или обрыв оптического канала нужно воспринимать как должное и учитывать при проведении работ. Я предлагаю обратить внимание на этот факт в контексте выбора проверок успешности этапов миграции. Как бы парадоксально это не звучало, в данном случае нам не обязательно проверять появилось ли OSPF соседство на том или ином интерфейсе, так как причины его отсутствия могут находится совсем в другой плоскости. Кроме перечисленного выше в исходные данные всегда может попасть ошибка или неточность, например, например, в виде всеми забытого интерфейса, который подлежит удалению, а в данный момент смотрит в «пустоту». В процессе формирования проверок полезно подняться на уровень выше, чтобы посмотреть на сеть с точки зрения оказываемых услуг и наложенных протоколов, так как в конечном счете состояние только этих вещей позволяет принять обоснованное решение об успешности того или иного этапа. Мало кто из заказчиков соглашается на публичные статьи по результатам выполненных работ, еще и поэтому я собрал виртуальную среду для демонстрации. В рамках этой среды я ограничусь проверкой состояния BGP сессий, которые построены по схеме каждый-с-каждым между маршрутизаторами, это и будет нашими наложенными сервисами, и услугами. Если, после работ выполняются условия для их работоспособности в виде IP связности каждый-с-каждым, значит есть и основания полагать что работы проведены успешно. В реальных проектах проверки обычно ограничиваются тем объемом услуг и наложенных протоколов, которые обозначается как business critical в данной сети. К программированию это не относится, тем не менее я не могу не заострить внимание на этом вопросе, так как выбор критерия успешности — это залог спокойного сна после проведенных работ.

Код проверки BGP сессий

import sys
import yaml
from jnpr.junos.factory.factory_loader import FactoryLoader
from jnpr.junos import Device

def getConnection(p_host, p_user):
    acc = {’lab’: ’lab123′}

    try:
        print ’        DEBUG — getting ssh connection to ’ + p_host

        l_dev = Device(host=p_host, user=p_user, password=acc[p_user], auto_probe=2, gather_facts=True, port=22)
        l_dev.open()
        if (l_dev.connected):
            l_dev.timeout = 900
            print ’    DEBUG — ssh cionnection to host ’ + p_host + ’ established’
            print ’    DEBUG — connection ’ + p_host + ’ named ’ + l_dev.facts[’hostname’] + ’ established ’
            return l_dev
    else:
            raise Exception(’    DEBUG — ssh connection to ’ + p_host + ’ was not established’)
    except Exception as ex:
            print ’    DEBUG — ERROR — getConnection : connection to ’ + p_host + ’ was not established. ex:’ + str(ex)
            return

def close_dev(d):
    try:
        d.close()
    except Exception as ex:
        print ’        DEBUG — ERROR — close_dev : connection to cant be closed. ex:’ + str(ex)

ip_f_name = ’ip-list-1.txt’

yml = ’’’

BGPGroup:
  rpc: get-bgp-group-information
  args:
   group-name: ’int’
  item: bgp-group
  view: BGPGroupView

BGPGroupView:
  fields:
   count: peer-count
   established: established-count
’’’

globals().update(FactoryLoader().load(yaml.load(yml)))

node_list = [’10.83.20.68′, ’10.83.20.69′, ’10.83.20.70′, ’10.83.20.71′]
abr_list = [’10.83.20.66′, ’10.83.20.67′]

for node in node_list + abr_list:
            ddev = getConnection(node, ’lab’)
            bgp_group = BGPGroup(ddev).get()

            for group in bgp_group:
                        if (group.count != group.established):
                                    print ’bgp connection lost’
                        else:
                                    print ’dont panic!’


Результаты его работы DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
dont panic!
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
dont panic!
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
dont panic!
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
dont panic!
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
dont panic!
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
dont panic!

До текущего момента мы беседовали по большей части о каких-то сетевых вещах, но я еще ни словом ни обмолвился о программном коде, который вроде как должен быть в центре внимания в статье с таким названием. Во-первых, мне кажется, что мысли намного важнее кода, формализовав сущности в голове инженер сможет превратить их в инструмент и изложить в виде кода. Во-вторых, мне не хочется повторятся, все что может показаться не очевидным в этих примерах, а также минимально необходимые знания для начала работы с Python и Pyez, содержатся в предыдущей статье цикла. В-третьих, код подготовки конфигурации осуществляет свою работу, что называется в офлайне и не оказывает мгновенного воздействия на сеть, поэтому вряд ли может вызвать какой-то интерес. Несколько иначе обстоят дела с кодом имплементации этапа исполнения, разработка этих процедур ставит перед нами следующие вопросы:

  • Как проверить что весь объем команд адекватно восприняты интерпретатором?
  • Как проверить что вносимые в конфигурацию изменения были применены?
  • Как осуществить транзакционную схему внесения конфигурации?
  • Как сделать откат конфигурации в случае потери управления?
  • Как почистить за собой если в процессе передачи команд интерпретатор сообщил об ошибке?

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

Вооружившись документацией по Pyez был составлен следующий код универсального загрузчика конфигурации, который вы можете использовать в своей повседневной работе, так же как я использую его в своей.

conf_change.py

import sys
import yaml
from jnpr.junos.factory.factory_loader import FactoryLoader
from jnpr.junos import Device
from jnpr.junos.utils.config import Config
import copy
import re
import traceback
import time
import random
from jnpr.junos.exception import *
import os.path

yml = ’’’

VersionInfo:
rpc: get-software-information
item: software-information
view: VersionInfoView

VersionInfoView:
fields:
name: host-name

’’’
Device.auto_probe = 3

ip_f_name = ’ip-list-1.txt’
cur_stage=’2′

globals().update(FactoryLoader().load(yaml.load(yml)))

def doTestOSPF(p_dev, p_node, f_do):
print ’ DEBUG — doTestOSPF : at ’ + p_node
if ( p_dev == None ):
print ’ DEBUG — ERROR — doTestOSPF : connection to ’ + p_node + ’ is None’
return
else:
try:
d_conf = p_dev.cli(«show configuration | display set«).split(’\n’)
ret_val = True
set_found = 0
c_path = ’st’ + cur_stage + ’-’ + p_node + ’.txt’
with open(c_path, «r») as f:
for line in f:
c_line = line.replace(’\n’, ’’).replace(’\r\n’, ’’)
if (’delete ’ not in c_line):
set_found = 1
if ( (c_line not in d_conf) and (c_line != ’’)):
print ’ DEBUG — doTestOSPF found missing line ’ + c_line
ret_val = False


f.close()
if ( (set_found == 0) and (f_do == True) ):
return False
return ret_val
except Exception as ex:
print ’ DEBUG — ERROR — doTestOSPF : connection to ’ + p_node + ’ was not established. ex:’ + str(ex)
return

def doTest(p_dev, p_node, f_do):
return doTestOSPF(p_dev, p_node, f_do)

def close_dev(d):
try:
d.close()
except Exception as ex:
print ’ DEBUG — ERROR — close_dev : connection to cant be closed. ex:’ + str(ex)

def getConnection(p_host, p_user):
acc = {’lab’: ’lab123′}

try:
print ’ DEBUG — getting ssh connection to ’ + p_host

l_dev = Device(host=p_host, user=p_user, password=acc[p_user], auto_probe=2, gather_facts=True, port=22)
l_dev.open()
if (l_dev.connected):
l_dev.timeout = 900
print ’ DEBUG — ssh cionnection to host ’ + p_host + ’ established’
v = VersionInfo(l_dev).get()
print ’ DEBUG — connection ’ + p_host + ’ named ’ + l_dev.facts[’hostname’] + ’ established ’
return l_dev
else:
raise Exception(’ DEBUG — ssh connection to ’ + p_host + ’ was not established’)
except Exception as ex:
print ’ DEBUG — ERROR — getConnection : connection to ’ + p_host + ’ was not established. ex:’ + str(ex)
traceback.print_exc()
return

def doCompare(p_conf, p_node):
try:
print ’ DEBUG — doCompare at ’ + p_node
if ( p_conf.diff() == None ):
return False
else:
return True
except Exception as ex:
print ’ DEBUG — ERROR — doCompare : conf.diff at ’ + p_node + ’ ex:’ + str(ex)
return

def doLoad(p_conf, p_node):
try:
print ’ DEBUG — doLoad at ’ + p_node

c_path = ’st’ + cur_stage + ’-’ + p_node + ’.txt’
if (os.path.isfile(c_path)):
p_conf.load(path=c_path, format=’set’)

return True
except Exception as ex:
print ’ DEBUG — ERROR — doLoad : cant load config to ’ + p_node + ’ ex:’ + str(ex)
return

def doRollback(p_conf, p_node, p_r):
try:
print ’ DEBUG — doRollback at ’ + p_node
if ( p_conf.rollback(rb_id=p_r) == True ):
return True
else:
return False
except Exception as ex:
print ’ DEBUG — ERROR — doRollback : cant rollback config to ’ + p_node + ’ ex:’ + str(ex)
return None

def doCommitCheck(p_conf, p_node):
try:
print ’ DEBUG — doCommitCheck at ’ + p_node
p_conf.commit_check()
return True
except Exception as ex:
print ’ DEBUG — ERROR — doCommitCheck : cant config commit check config to ’ + p_node + ’ ex:’ + str(ex)
return None

def doCommit(p_conf, p_node, p_confirm_m=None):
try:
print ’ DEBUG — doCommit at ’ + p_node
commit_res = None
if (p_confirm_m == None):
commit_res = p_conf.commit(timeout=30)
else:
commit_res = p_conf.commit(confirm=p_confirm_m, timeout=30)

if (commit_res == True):
return True
else:
return False
except CommitError as c_ex:
print ’ DEBUG — ERROR — doCommit : cant config commit at ’ + p_node + ’ ex:’ + str(c_ex)
return None
except RpcTimeoutError as t_ex:
print ’ DEBUG — ERROR — doCommit : config was commited at ’ + p_node + ’ with the following ex:’ + str(t_ex)
return True

def doJob(p_dev, p_node):
print ’ DEBUG — doJob at ’ + p_node
if ( p_dev == None ):
print ’ DEBUG — ERROR — doJob : connection to ’ + p_node + ’ is None’
return
else:
try:
with Config(p_dev) as conf:
is_compare = doCompare(conf, node)
if ( is_compare == None ):
print ’ DEBUG — ERROR — doJob : at config compare ’ + node
return
if ( is_compare == True ):
print ’ DEBUG — ERROR — doJob : configuration locked at ’ + node
return False
print ’ DEBUG — starting to do config changes at ’ + node
if ( doLoad(conf, node) != True ):
print ’ DEBUG — ERROR — doJob : conf.load ’ + node
if ( doCompare(conf, node) != False ):
print ’ DEBUG — doJob : doing rollback after load at ’ + node + ’ deleting :’ + str(conf.diff())
doRollback(conf, node, 0)
return
print ’ DEBUG — commit check at ’ + node
if (doCommitCheck(conf, node) != True):
print ’ DEBUG — ERROR — doJob : conf.doCommitCheck failed at ’ + node
if ( doCompare(conf, node) != False ):
print ’ DEBUG — doJob : doing rollback after load at ’ + node + ’ deleting :’ + str(conf.diff())
doRollback(conf, node, 0)
return
commit_m = 5
print ’ DEBUG — commiting changes at ’ + node
if (doCommit(conf, node, commit_m) != True):
print ’ DEBUG — ERROR — doJob : conf.commit ’ + node
if ( doCompare(conf, node) != False ):
print ’ DEBUG — doJob : doing rollback after commit at ’ + node + ’ deleting :’ + str(conf.diff())
doRollback(conf, node, 0)
return True
except Exception as ex:
print ’ DEBUG — ERROR — doJob : cant do job ’ + node + ’ ex:’ + str(ex)
return

node_list = []
result_list = {}

with open(ip_f_name, «r») as f_ip:
for line in f_ip:
c_ip_line = line.replace(’\n’, ’’).replace(’\r\n’, ’’)
if (c_ip_line != ’’):
node_list.append(c_ip_line)

for node in node_list:
print ’FLOW — ************************************ ’
print ’FLOW — checking ’ + node
result_list.setdefault(node, {})
cur_dev = getConnection(node, ’lab’)
is_test = doTest(cur_dev, node, True)
if( is_test == None):
print ’FLOW — error’
result_list.setdefault(node, {}).setdefault(’status’, ’error’)
break
if( is_test == True):
print ’FLOW — conf exist’
result_list.setdefault(node, {}).setdefault(’status’, ’nn’)
if( is_test == False):
print ’FLOW — conf not exist, doing change’
is_job = doJob(cur_dev, node)
if( is_job == None):
print ’FLOW — cant do job at ’ + node
result_list.setdefault(node, {}).setdefault(’status’, ’error’)
break
if( is_job == False):
print ’FLOW — cant do job at ’ + node
result_list.setdefault(node, {}).setdefault(’status’, ’not_done’)
if( is_job == True):
print ’FLOW — done job at ’ + node
print ’FLOW — going sleep at ’ + node
time.sleep(5)
print ’FLOW — checking job status ’ + node
cur_dev_confirm = getConnection(node, ’lab’)
if ( cur_dev_confirm != None ):
if (doTest(cur_dev, node, False) == True):
print ’FLOW — commiting the configuration at ’ + node
if (doCommit(Config(cur_dev_confirm), node) != True):
print ’FLOW — ERROR cant commit the configuration at ’ + node
result_list.setdefault(node, {}).setdefault(’status’, ’not_done’)
break
else:
print ’FLOW — configuration commited at ’ + node
result_list.setdefault(node, {}).setdefault(’status’, ’done’)
else:
print ’FLOW — ERROR cant find conf after job ’ + node
result_list.setdefault(node, {}).setdefault(’status’, ’not_done’)
close_dev(cur_dev_confirm)
else:
print ’FLOW — ERROR cant access ’ + node + ’ for commiting’
result_list.setdefault(node, {}).setdefault(’status’, ’not_done’)
close_dev(cur_dev)

print result_list

И результаты его работы по трем этапам

Скрытый текст

Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32
Type «copyright», «credits» or «license()» for more information.
>>>
==== RESTART: C:\Users\and_andreev\Desktop\tools\lab-case2\conf_change.py ====
FLOW — ************************************
FLOW — checking 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.66
DEBUG — doCompare at 10.83.20.66
DEBUG — starting to do config changes at 10.83.20.66
DEBUG — doLoad at 10.83.20.66
DEBUG — commit check at 10.83.20.66
DEBUG — doCommitCheck at 10.83.20.66
DEBUG — commiting changes at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — done job at 10.83.20.66
FLOW — going sleep at 10.83.20.66
FLOW — checking job status 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
FLOW — commiting the configuration at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — configuration commited at 10.83.20.66
FLOW — ************************************
FLOW — checking 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.67
DEBUG — doCompare at 10.83.20.67
DEBUG — starting to do config changes at 10.83.20.67
DEBUG — doLoad at 10.83.20.67
DEBUG — commit check at 10.83.20.67
DEBUG — doCommitCheck at 10.83.20.67
DEBUG — commiting changes at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — done job at 10.83.20.67
FLOW — going sleep at 10.83.20.67
FLOW — checking job status 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
FLOW — commiting the configuration at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — configuration commited at 10.83.20.67
FLOW — ************************************
FLOW — checking 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.68
DEBUG — doCompare at 10.83.20.68
DEBUG — starting to do config changes at 10.83.20.68
DEBUG — doLoad at 10.83.20.68
DEBUG — commit check at 10.83.20.68
DEBUG — doCommitCheck at 10.83.20.68
DEBUG — commiting changes at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — done job at 10.83.20.68
FLOW — going sleep at 10.83.20.68
FLOW — checking job status 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
FLOW — commiting the configuration at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — configuration commited at 10.83.20.68
FLOW — ************************************
FLOW — checking 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.69
DEBUG — doCompare at 10.83.20.69
DEBUG — starting to do config changes at 10.83.20.69
DEBUG — doLoad at 10.83.20.69
DEBUG — commit check at 10.83.20.69
DEBUG — doCommitCheck at 10.83.20.69
DEBUG — commiting changes at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — done job at 10.83.20.69
FLOW — going sleep at 10.83.20.69
FLOW — checking job status 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
FLOW — commiting the configuration at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — configuration commited at 10.83.20.69
FLOW — ************************************
FLOW — checking 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/0.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.70
DEBUG — doCompare at 10.83.20.70
DEBUG — starting to do config changes at 10.83.20.70
DEBUG — doLoad at 10.83.20.70
DEBUG — commit check at 10.83.20.70
DEBUG — doCommitCheck at 10.83.20.70
DEBUG — commiting changes at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — done job at 10.83.20.70
FLOW — going sleep at 10.83.20.70
FLOW — checking job status 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
FLOW — commiting the configuration at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — configuration commited at 10.83.20.70
FLOW — ************************************
FLOW — checking 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/1.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/2.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface ge-0/0/3.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.71
DEBUG — doCompare at 10.83.20.71
DEBUG — starting to do config changes at 10.83.20.71
DEBUG — doLoad at 10.83.20.71
DEBUG — commit check at 10.83.20.71
DEBUG — doCommitCheck at 10.83.20.71
DEBUG — commiting changes at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — done job at 10.83.20.71
FLOW — going sleep at 10.83.20.71
FLOW — checking job status 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
FLOW — commiting the configuration at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — configuration commited at 10.83.20.71
{’10.83.20.70′: {’status’: ’done’}, ’10.83.20.71′: {’status’: ’done’}, ’10.83.20.67′: {’status’: ’done’}, ’10.83.20.66′: {’status’: ’done’}, ’10.83.20.69′: {’status’: ’done’}, ’10.83.20.68′: {’status’: ’done’}}
>>>
>>>
>>>
==== RESTART: C:\Users\and_andreev\Desktop\tools\lab-case2\conf_change.py ====
FLOW — ************************************
FLOW — checking 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.66
DEBUG — doCompare at 10.83.20.66
DEBUG — starting to do config changes at 10.83.20.66
DEBUG — doLoad at 10.83.20.66
DEBUG — commit check at 10.83.20.66
DEBUG — doCommitCheck at 10.83.20.66
DEBUG — commiting changes at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — done job at 10.83.20.66
FLOW — going sleep at 10.83.20.66
FLOW — checking job status 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
FLOW — commiting the configuration at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — configuration commited at 10.83.20.66
FLOW — ************************************
FLOW — checking 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 metric 1
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.67
DEBUG — doCompare at 10.83.20.67
DEBUG — starting to do config changes at 10.83.20.67
DEBUG — doLoad at 10.83.20.67
DEBUG — commit check at 10.83.20.67
DEBUG — doCommitCheck at 10.83.20.67
DEBUG — commiting changes at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — done job at 10.83.20.67
FLOW — going sleep at 10.83.20.67
FLOW — checking job status 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
FLOW — commiting the configuration at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — configuration commited at 10.83.20.67
FLOW — ************************************
FLOW — checking 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface lo0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface lo0.0 secondary
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.68
DEBUG — doCompare at 10.83.20.68
DEBUG — starting to do config changes at 10.83.20.68
DEBUG — doLoad at 10.83.20.68
DEBUG — commit check at 10.83.20.68
DEBUG — doCommitCheck at 10.83.20.68
DEBUG — commiting changes at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — done job at 10.83.20.68
FLOW — going sleep at 10.83.20.68
FLOW — checking job status 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
FLOW — commiting the configuration at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — configuration commited at 10.83.20.68
FLOW — ************************************
FLOW — checking 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/0.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/0.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface lo0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface lo0.0 secondary
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.69
DEBUG — doCompare at 10.83.20.69
DEBUG — starting to do config changes at 10.83.20.69
DEBUG — doLoad at 10.83.20.69
DEBUG — commit check at 10.83.20.69
DEBUG — doCommitCheck at 10.83.20.69
DEBUG — commiting changes at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — done job at 10.83.20.69
FLOW — going sleep at 10.83.20.69
FLOW — checking job status 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
FLOW — commiting the configuration at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — configuration commited at 10.83.20.69
FLOW — ************************************
FLOW — checking 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/0.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/0.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface lo0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface lo0.0 secondary
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.70
DEBUG — doCompare at 10.83.20.70
DEBUG — starting to do config changes at 10.83.20.70
DEBUG — doLoad at 10.83.20.70
DEBUG — commit check at 10.83.20.70
DEBUG — doCommitCheck at 10.83.20.70
DEBUG — commiting changes at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — done job at 10.83.20.70
FLOW — going sleep at 10.83.20.70
FLOW — checking job status 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
FLOW — commiting the configuration at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — configuration commited at 10.83.20.70
FLOW — ************************************
FLOW — checking 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/1.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/2.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 secondary
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface ge-0/0/3.0 metric 1
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.250 interface lo0.0 interface-type p2p
DEBUG — doTestOSPF found missing line set protocols ospf area 0.0.0.200 interface lo0.0 secondary
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.71
DEBUG — doCompare at 10.83.20.71
DEBUG — starting to do config changes at 10.83.20.71
DEBUG — doLoad at 10.83.20.71
DEBUG — commit check at 10.83.20.71
DEBUG — doCommitCheck at 10.83.20.71
DEBUG — commiting changes at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — done job at 10.83.20.71
FLOW — going sleep at 10.83.20.71
FLOW — checking job status 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
FLOW — commiting the configuration at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — configuration commited at 10.83.20.71
{’10.83.20.70′: {’status’: ’done’}, ’10.83.20.71′: {’status’: ’done’}, ’10.83.20.67′: {’status’: ’done’}, ’10.83.20.66′: {’status’: ’done’}, ’10.83.20.69′: {’status’: ’done’}, ’10.83.20.68′: {’status’: ’done’}}
>>>
==== RESTART: C:\Users\and_andreev\Desktop\tools\lab-case2\conf_change.py ====
FLOW — ************************************
FLOW — checking 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.66
DEBUG — doCompare at 10.83.20.66
DEBUG — starting to do config changes at 10.83.20.66
DEBUG — doLoad at 10.83.20.66
DEBUG — commit check at 10.83.20.66
DEBUG — doCommitCheck at 10.83.20.66
DEBUG — commiting changes at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — done job at 10.83.20.66
FLOW — going sleep at 10.83.20.66
FLOW — checking job status 10.83.20.66
DEBUG — getting ssh connection to 10.83.20.66
DEBUG — ssh cionnection to host 10.83.20.66 established
DEBUG — connection 10.83.20.66 named abr1 established
DEBUG — doTestOSPF : at 10.83.20.66
FLOW — commiting the configuration at 10.83.20.66
DEBUG — doCommit at 10.83.20.66
FLOW — configuration commited at 10.83.20.66
FLOW — ************************************
FLOW — checking 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.67
DEBUG — doCompare at 10.83.20.67
DEBUG — starting to do config changes at 10.83.20.67
DEBUG — doLoad at 10.83.20.67
DEBUG — commit check at 10.83.20.67
DEBUG — doCommitCheck at 10.83.20.67
DEBUG — commiting changes at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — done job at 10.83.20.67
FLOW — going sleep at 10.83.20.67
FLOW — checking job status 10.83.20.67
DEBUG — getting ssh connection to 10.83.20.67
DEBUG — ssh cionnection to host 10.83.20.67 established
DEBUG — connection 10.83.20.67 named abr2 established
DEBUG — doTestOSPF : at 10.83.20.67
FLOW — commiting the configuration at 10.83.20.67
DEBUG — doCommit at 10.83.20.67
FLOW — configuration commited at 10.83.20.67
FLOW — ************************************
FLOW — checking 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.68
DEBUG — doCompare at 10.83.20.68
DEBUG — starting to do config changes at 10.83.20.68
DEBUG — doLoad at 10.83.20.68
DEBUG — commit check at 10.83.20.68
DEBUG — doCommitCheck at 10.83.20.68
DEBUG — commiting changes at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — done job at 10.83.20.68
FLOW — going sleep at 10.83.20.68
FLOW — checking job status 10.83.20.68
DEBUG — getting ssh connection to 10.83.20.68
DEBUG — ssh cionnection to host 10.83.20.68 established
DEBUG — connection 10.83.20.68 named r1 established
DEBUG — doTestOSPF : at 10.83.20.68
FLOW — commiting the configuration at 10.83.20.68
DEBUG — doCommit at 10.83.20.68
FLOW — configuration commited at 10.83.20.68
FLOW — ************************************
FLOW — checking 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.69
DEBUG — doCompare at 10.83.20.69
DEBUG — starting to do config changes at 10.83.20.69
DEBUG — doLoad at 10.83.20.69
DEBUG — commit check at 10.83.20.69
DEBUG — doCommitCheck at 10.83.20.69
DEBUG — commiting changes at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — done job at 10.83.20.69
FLOW — going sleep at 10.83.20.69
FLOW — checking job status 10.83.20.69
DEBUG — getting ssh connection to 10.83.20.69
DEBUG — ssh cionnection to host 10.83.20.69 established
DEBUG — connection 10.83.20.69 named r2 established
DEBUG — doTestOSPF : at 10.83.20.69
FLOW — commiting the configuration at 10.83.20.69
DEBUG — doCommit at 10.83.20.69
FLOW — configuration commited at 10.83.20.69
FLOW — ************************************
FLOW — checking 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.70
DEBUG — doCompare at 10.83.20.70
DEBUG — starting to do config changes at 10.83.20.70
DEBUG — doLoad at 10.83.20.70
DEBUG — commit check at 10.83.20.70
DEBUG — doCommitCheck at 10.83.20.70
DEBUG — commiting changes at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — done job at 10.83.20.70
FLOW — going sleep at 10.83.20.70
FLOW — checking job status 10.83.20.70
DEBUG — getting ssh connection to 10.83.20.70
DEBUG — ssh cionnection to host 10.83.20.70 established
DEBUG — connection 10.83.20.70 named r3 established
DEBUG — doTestOSPF : at 10.83.20.70
FLOW — commiting the configuration at 10.83.20.70
DEBUG — doCommit at 10.83.20.70
FLOW — configuration commited at 10.83.20.70
FLOW — ************************************
FLOW — checking 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
FLOW — conf not exist, doing change
DEBUG — doJob at 10.83.20.71
DEBUG — doCompare at 10.83.20.71
DEBUG — starting to do config changes at 10.83.20.71
DEBUG — doLoad at 10.83.20.71
DEBUG — commit check at 10.83.20.71
DEBUG — doCommitCheck at 10.83.20.71
DEBUG — commiting changes at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — done job at 10.83.20.71
FLOW — going sleep at 10.83.20.71
FLOW — checking job status 10.83.20.71
DEBUG — getting ssh connection to 10.83.20.71
DEBUG — ssh cionnection to host 10.83.20.71 established
DEBUG — connection 10.83.20.71 named r4 established
DEBUG — doTestOSPF : at 10.83.20.71
FLOW — commiting the configuration at 10.83.20.71
DEBUG — doCommit at 10.83.20.71
FLOW — configuration commited at 10.83.20.71
{’10.83.20.70′: {’status’: ’done’}, ’10.83.20.71′: {’status’: ’done’}, ’10.83.20.67′: {’status’: ’done’}, ’10.83.20.66′: {’status’: ’done’}, ’10.83.20.69′: {’status’: ’done’}, ’10.83.20.68′: {’status’: ’done’}}
>>>

  1. The Complete IS-IS Routing Protocol — Hannes Gredler, Walter Goralski
  2. OSPF; Anatomy of an Internet Routing Protocol — John T. Moy
  3. Network Mergers and Migrations: Junos Design and Implementation — Gonzalo Gomez Herrero, Jan Anton Bernal Van Der Ven
  4. OSPF Multi-Area Adjacency —tools.ietf.org/html/rfc5185

Что Ethernet-инженеру нужно знать о UML


Что же Ethernet-инженеру нужно знать о UML (Unified Modeling Language)? Да в целом ничего. ) Но это был бы слишком короткий пост… Давненько я не графоманил, так что для начала немного философии. Если вы не хотите читать мои размышления, то вы можете пропустить N абзацов и перейти к заголовку «Что же такое UML?».

Философия

На самом деле, в наше время само понятие сетевого инженера несколько меняется. Я буквально на своей шкуре ощущаю эту метаморфозу. Связаны эти изменения с изменением самих сетей. Если раньше сеть представляла из себя набор сетевых элементов, и в лучшем случае, эти сетевые элементы были объединены некой NMS (EMS). То сейчас, с появлением NFV и SDN, ситуация меняется. Сеть уже начинает восприниматься несколько иначе. Как вы знаете, в SDN сетевые элементы сами по себе уже не определяют поведение всей сети, решение принимает некий контроллер. Речь идет про самое прямое понимание SDN. А в NFV, часть сетевых функций, ну скажем NAT, переносится на обычные виртуалки. Это два довольно больших аспекта, которые меняют представление о сетях. Два понятия часто идут вместе и описывают некий новый путь построения сетей. Иногда, даже когда нет в сети никаких контроллеров, но есть часть виртуализированных функций, все равно употребляют термин SDN/NFV.

Возможно, вы думаете, что все это происходит в лабораторных, институтах и прочих заведениях. Однако, SDN и NFV уверенно шагает по планетке. Если вы с ними не сталкиваетесь, это не значит, что они к вам не приближаются со спины.

Я столкнулся ещё с одной особенностью, которая была полнейшей неожиданностью для меня. У нас в стране, как мне кажется, есть стойкая тенденция управлять сетью руками. За бугром же, совершенно четко видно, что управлять железом непосредственно выглядит дикостью. В мире правят OSS системы, которые позволяют управлять сетью как единым целым. Конечно, это не является правилом. Это скорее мои наблюдения, которые основаны на некотором опыте.

К чему же я развел философию? К тому, что сетевой инженер нынче должен мыслить немного другими формами. Ну, как мне кажется, как минимум хороший сетевой инженер. Уверенные знания сетевых протоколов и вообще поведения сетей необходимы, но этого уже недостаточно. Современный сетевичек должен быть немного программистом и, если не уметь что-то написать, то хотя бы понимать, как вообще происходит весь процесс программирования. Не лишним будет представлять принципы объектно-ориентированного программирования, знать что такое базы данных и с чем их едят, понимать как работать с системами через API и все в этом духе. 

Могу привести пример. Вы сетевой инженер в современной(!) компании. Ваша компания, как стремящаяся идти в ногу со временем, решает сократить капитальные расходы уведя часть сетевых функций в виртуальную среду (NFV). SDN в чистом виде вы не используете, пока что. В вашей конторе используются, к примеру, свеженькие Cisco ASR, мои любимые коммутаторы Extreme Networks и виртуальные файерволы от компании Palo Alto. Так же, часть функций вы подняли на виртуальных Juniper. И тут ваша компания решает соответствовать модным тенденциям и сократить расходы на персонал, что в целом разумно, если соблюдать баланс. Двух ваших коллег решено уволить, а вы с флагом в руках подписаны на оптимизацию процессов в вашей компании. Отныне, не ваши коллеги будут лопатить конфиги руками на сети, и даже не вы сами. Лопатить все будет некая система. Пусть это и набор питоновских скриптов, мы все равно назовем это системой. Вы, как не программист, не должны её писать. Однако вы должны объяснить людям как её писать, что она должна делать, и как она должна вести себя в той или иной ситуации. Поверьте, «чистому» сетевику очень сложно говорить с «чистым» программистом. Вы просто говорите на разных языках, вот и все. Говорить на одном языке вы не можете по причине того, что вы просто оперируете разными понятиями. Он вам твердит про объекты и атрибуты, а вы ему про железки и SFPшки. Что делать? Вопрос сложный. Идеальный вариант, вам нужно двигаться навстречу. Программисту узнавать как работают сети, а вам потихоньку разбираться в том, что же вам говорит программист. Конечно, ваш коллега-программист может и не захотеть двигаться вам навстречу. И это его проблемы. Вы то понимаете, что это неправильно. Поэтому вы должны узнавать больше. ) Накипело, видать, у меня. Тут мы подходим к теме поста. Помочь вам в общении сможет UML.

Что же такое UML? 

Это унифицированный язык моделирования. Я не большой спец в нем, я только учусь, но название говорит само за себя. В теории, это способ объяснить что-либо другому человеку. UML покрывает довольно большое количество сценариев. В целом, когда вы в школе на информатике (я надеюсь) рисовали алгоритмы, это был почти UML. Сама нотация не привносит ничего нового, она лишь стандартизирует способы подачи информации в графическом виде. Сама идея состоит в том, что даже неподготовленный человек должен быть в состоянии понять то, что изображено в UML диаграмме. Она должна быть ясна и понятна для неподготовленного человека. Если же человек что-то понимает в UML, диаграмма должна предоставить ему лишь какие-то дополнительные сведения. Базовый смысл остается неизменным. Это в теории.

В UML великое множество типов диаграмм, но все они делятся на две больших категории.

  • Structural (структурные) показывают структуру; 
  • Behavior (поведенческие) изображают поведение.

Близким к сетевику примером первой категории может быть диаграмма-изображение шасси, карт, слотов и прочей физической утвари современной железяки. Для второй категории подойдет в качестве примера диаграмма установления BGP-сессии или, скажем, в более сложном случае алгоритм-диаграмма настройки какого-либо сервиса. Все это мы и рассмотрим чуть ниже. 

Следуя моему красочному примеру, в котором вы одни призваны автоматизировать работу отдела, нам надо описать/обрисовать следующие случаи для отдела разработки.

  1. Взаимоотношения между физическими сущностями в железке. Возьмем старичка Cisco 6509. 
  2. Какие виды активностей вообще существуют в сети. Прокинуть влан, настроить порт, поднять пиринг с кем-нибудь.
  3. Как должно быть организовано взаимоотношение между системами. Как новая система должна обращаться к сети, какие ответы от неё ждать и прочее.
  4. Как система должны вести себя. Нужен реальный алгоритм, если порт в состоянии Down, перевести в Up, сбросить настройки, прокинуть VLAN, создать его и прочее.

Ясно, что все задачи выше хоть и приближены к жизни, но довольно рафинированные. Просто потому что я хочу описать  в посте пример, а не начинать разработку полноценного ПО. )

Для наших целей подойдут следующие виды диаграмм:

  1. Component diagram. Диаграммы компонентов в русском варианте. Штука это довольно сложная, но мы как не программисты, упраздним половину ненужного и постараемся изобразить, как части железки относятся к друг другу.
  2. Use cases diagram. Диаграмма сценариев использования. Должна помочь нам изобразить, что вообще оператор творит с сетью, что нужно автоматизировать.
  3. Sequence diagram. Диаграмма последовательности. Тут мы опишем, как наша новая система будем взаимодействовать с сетью, что спрашивать и что ждать в ответ.
  4. Activity diagram. Диаграмма активностей. Это как раз как в школе, с ромбиками и прямоугольничками. Отражает детальную логику поведения системы.

Ещё раз замечу, что в UML великое множество видов диаграмм и все они так или иначе заточены под программирование и разработку ПО. С полным списком вы можете ознакомиться на просторах Интернета. Возможно, можно использовать другие типы диаграмм для наших примеров. Если вы их найдете, я буду только рад. На правду в последней инстанции не претендую, да и какая разница как все эти типы называются.

Component diagram
Начнем с простого. Давайте для возьмем Cisco Catalyst 6509. Мы знаем, что это шасси, в которое можно воткнуть какие-то модули. Модули бывают разные. Есть вентиляторы, есть блоки питания, есть процессоры, есть линейные карты. Более того, в линейные карты можно воткнуть SFPшки или иные трансиверы, а на процессорном модуле можно сменить память или, скажем, поставить другую фиче-карту (PFC). После того как вы расскажите это программисту, он расстроится и попросит вас это нарисовать. ) Чем и займемся.

Для изображения объектов мы будем использовать просто прямоугольник, а для того чтобы показать взаимотношение объектов будем использовать разные стрелки. В UML вообще миллион всяких стрелок, но мы то мало что про него знаем, поэтому ограничимся несколькими. Описание смотрите под картинкой.

Руками рисовать будет долго, поэтому воспользуемся услугами draw.io. Это неполное представление железной части 6509 в моем исполнении. Конечно, многое можно перерисовать, много можно дополнить. Схему можно делать как подробной, так и чисто ознакомительной. Я в какой-то момент понял, что начинаю уставать и ограничился детализацией «до порта». Бытро пробежимся сверху вниз.
  1. Сверху мы имеем объект — шасси 6509. Все, что расположено ниже, содержиться в этом шасси. Одно шасси имеет 2 слота под блоки питания. Для такого типа отношений есть специальная трелка с ромбиком. Вы можете видеть цифры у стрелок, они как раз и дают понимание о количественных показателях. Одно шасси содержит в себе 9 слотов и один слот для вентиляторов.
  2. Спускаемся на уровень ниже. Один или два блока питания используют один или два слота под них. Я написал 1 или 2, но можно было бы написать 0 или 2. В шасси, в общем-то, пожно и не втыкать вообще блоков питания, но я посчитал это слишком уж оторванным от жизни. Одна или две карты CPU используют один или два общих слота. Ноль или семь оставшихся слотов могут занять семь карт, а могут и не занять (0-7). И так далее…
  3. Ещё на уровень ниже. Тут можно увидеть, что CPU карта всегда имеет MSFS карту, PFC слот и один или много портов. 
  4. И так далее…
Повторюсь, детализировать можно до винтика, но тут важно показать принцип. Ну и рисовал по памяти, мог что-то перепутать в архитектуре 6509.
Use cases diagram
Тут постараемся изобразить, что именно должна уметь наша система и какие пользователи будут иметь доступ к её функциям. Например, помимо автоматической настройки наших устройств, вы, как сетевой инженер, можете руками запустить какие-то процессы. А, например, специалист поддержки может посмотреть статус какого-то действия.
Диаграмма получилась, скажем прямо, так себе. Однако общий смысл все равно, я надеюсь, понятен. Мы, как Администратор, изображенный слева, можем запустить создание VLANа, его удаление и добавление на интерфейсы. Все эти процессы проходят в нашей системе The System. Эти три операции дополняет операция сохранения конфигурации, которую дополняет операция просмотра статуса. После добавления VLANа на интерфейс нужно проверить доступ до железки (если вы вдруг забыли добавить «add» в «switchport allowed vlan»). Эта операция дополняет операцию добавления VLANа на интерфейс. Инженеру поддержки мы как-то не очень доверяем, судя по всему. Именно по этому. он может только смотреть статус.
Sequence diagram
Возьмем самый простой случай прокидывания VLANа на железке. У нас есть:
  • оператор — смотрит за выполнением процесса, 
  • наша «система», которая выполняет какие-то операции, 
  • железка в сети, над которой происходят какие-то манипуляции. 
 Стрелки бывают обычные, которые изображают запрос, и пунктирные — ответ. 
Если кратко, то на схемке изображено начало процесса. Оператор запускает его, наша система запускает процесс создания VLANа (запрос самой к себе), потом отправляет первый запрос на железку. Далее следует фрейм с условием. В случае удачи, с сети придет SNMP-ответ, а в случае неудачи, сессия протухнет по таймауту. В этом случае, система известит об этом пользователя.
Activity diagram

Возьмем пример из прошлой диаграммы. Однако теперь нам надо описать логику поведения, а не то как части процесса общаются друг с другом. Тут все должно быть знакомо, если не влезать в тонкости. Активности в овалах, условия в ромбиках.


В рамках системы начинается процесс, сразу же система должна спросить параметры у пользователя (допустим, адрес и SNMP community). Если параметры не были получены, то вылетает ошибка и процесс прекращается. В положительном пути отправляется запрос на устройство. Если нет ответа, система снова вываливается с ошибкой. А вот если ответ получен, система обновляет статус операции и красиво завершается.


Вот как-то так можно использовать UML в будничной жизни современного сетевого инженера. Прошу прощения у программистов, которые прочитали этот пост. Возможно, я местами мог вас обидеть. Этого я делать никак не хотел. Давайте жить дружно. )

Python 3 SSH Network Automation Быстрый старт Python 3 SSH Network Automation Быстрый старт Линда курс китайских субтитров

Python 3 SSH Network Automation Быстрый старт китайских субтитров

Python 3 SSH Network Automation Быстрый запуск китайских субтитров

Python 3 SSH Network Automation Quick Start


Для сетевых инженеров, которые хотят использовать Secure Shell (SSH) для настройки своих сетевых устройств, Netmiko (библиотека Python, которая упрощает соединения SSH с сетевыми устройствами), является лучшим выбором.
В этом практическом курсе вы узнаете, как использовать Netmiko для автоматизации сети
Дэвид Бомбал помогает вам создавать и запускать различные сценарии при использовании Python, чтобы улучшить ваше понимание автоматизации сети
Узнайте, как создавать сценарии для программирования нескольких коммутаторов, как использовать Netmiko для программирования всей сети и т. д.






(оптимистичная электронная музыка) — [Лектор] Теперь переключатели в лаборатории хороши, но вы, возможно, не захотите что-либо делать в живой среде.
В среде реального времени вы можете использовать SSH для настройки сетевых устройств.
Есть много способов сделать это, и один из лучших способов SSH к сетевому устройству — использовать Netmiko.
Netmiko — это библиотека от нескольких поставщиков, которая упрощает подключение Paramiko SSH к сетевым устройствам.
Он поддерживает Python 2.7, Python 3.4 и Python 3.5.
Paramiko также позволяет вам подключаться к сетевым устройствам через SSH, но это не так просто и универсально, как Netmiko, поэтому я предлагаю вам использовать Netmiko вместо Paramiko, это то, что мы будем делать в этом курсе Используемый контент.
Netmiko поддерживает множество устройств, включая устройства Arista, устройства Cisco, устройства HP, устройства Juniper и Linux.
Эти устройства регулярно тестируются.
провел ограниченные тесты на других производителях и других устройствах и обеспечил экспериментальную поддержку этих устройств.
Netmiko с открытым исходным кодом, вы можете получить подробную информацию о Netmiko на GitHub.
Учебное руководство по Netmiko также можно использовать в качестве ссылки на GitHub.
Пример кода отображается на GitHub и поясняется код.
Однако в этом курсе я покажу вам, как подключиться к сетевому устройству с помощью SSH, поэтому я познакомлю вас с базовыми знаниями, которые помогут вам начать использовать Netmiko, поэтому я буду разбираться с каждым Этот скрипт позволяет начать использовать Netmiko для автоматизации сети.
Адрес загрузки этого видео курса:Быстрый запуск Python 3 SSH Network Automation

Pyneng Examples Exercises — Задания и примеры из книги «Python для сетевых инженеров»

Все примеры и задания были проверены на Python 3.7 и 3.8.

Как создать свой репозиторий для выполнения заданий

Подробнее о работе с Git и Github в книге

Создание репозитория на GitHub

Для создания своего репозитория на основе шаблона нужно:

  • залогиниться на GitHub
  • открыть репозиторий с заданиями
  • нажать «Use this template» и создать новый репозиторий на основе этого шаблона
  • в открывшемся окне надо ввести название репозитория
  • после этого готов новый репозиторий с копией всех файлов из исходного репозитория с заданиями

Клонирование репозитория с GitHub

Для локальной работы с репозиторием его нужно клонировать. Для этого используется команда git clone:

$ git clone [email protected]:natenka/pyneng-examples-exercises.git
Cloning into 'pyneng-examples-exercises'...
remote: Counting objects: 241, done.
remote: Compressing objects: 100% (191/191), done.
remote: Total 241 (delta 43), reused 239 (delta 41), pack-reused 0
Receiving objects: 100% (241/241), 119.60 KiB | 0 bytes/s, done.
Resolving deltas: 100% (43/43), done.
Checking connectivity... done.

По сравнению с приведённой в этом листинге командой, вам нужно изменить:

  • имя пользователя natenka на имя своего пользователя на GitHub;
  • имя репозитория pyneng-examples-exercises на имя своего репозитория на GitHub.

В итоге, в текущем каталоге, в котором была выполнена команда git clone, появится каталог с именем репозитория, в моём случае – «pyneng-examples-exercises». В этом каталоге теперь находится содержимое репозитория на GitHub.

Виртуалки

Для курса подготовлены два варианта виртуальных машин: vmware и Vagrant. По ссылке есть инструкции для каждого варианта, а также инструкция по выполнению заданий на Windows:

Задания

В каталоге exercises находятся задания к курсу, отсортированные по разделам курса. Кроме того, там находятся все вспомогательные файлы (конфигурации и др), которые используются в заданиях.

Если в заданиях раздела есть задания с буквами (например, 5.2a), то можно выполнить сначала задания без букв, а затем с буквами. Задания с буквами, как правило, немного сложнее заданий без букв и развивают/усложняют идею в соответствующем задании без буквы. Например, если в разделе есть задания: 5.1, 5.2, 5.2a, 5.2b, 5.3, 5.3a. Сначала, можно выполнить задания 5.1, 5.2, 5.3. А затем 5.2a, 5.2b, 5.3a. Однако, если задания с буквами получается сделать сразу, можно делать их по порядку.

Тесты

Начиная с раздела «9. Функции» для проверки заданий есть автоматические тесты. Они помогают проверить все ли соответствует поставленной задаче, а также дают обратный отклик по тому, что не соответствует задаче. Как правило, после первого периода адаптации к тестам, становится проще делать задания с тестами.

Для работы тестов, у вас должны быть установлены дополнительные библиотеки Python. Если вы работаете в виртуальном окружении, то Вы можете установить все требуюемые библиотеки следующим способом:
pip install -r requirements.txt

argparse — Документация Python для сетевых инженеров 1.0

argparse — это модуль для обработки аргументов командной строки. Примеры того, что модуль делает:

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

argparse — не единственный модуль для обработки аргументов командной строки.А также даже не единственный в стандартной библиотеке.

Эта книга охватывает только argparse , но вдобавок стоит взглянуть на модули, не входящие в стандартную библиотеку Python. Например, нажмите.

Примечание

Хорошая статья, сравнивает различные модули обработки аргументов командной строки (включая argparse, нажмите и скопируйте).

Пример скрипта ping_function.py:

 подпроцесс импорта
импортировать аргументы


def ping_ip (ip_address, количество):
    '''
    Пингуем IP-адрес и возвращаем кортеж:
    В случае успеха: (код возврата = 0, вывод команды)
    При ошибке: (код возврата, вывод ошибки (stderr))
    '''
    ответ = подпроцесс.бегать(
        'ping -c {счетчик} -n {ip}'.format(count=count, ip=ip_address),
        оболочка = Верно,
        стандартный вывод=подпроцесс.PIPE,
        stderr=подпроцесс.PIPE,
        кодировка = 'utf-8'
    )
    если ответ.код возврата == 0:
        вернуть True, ответить.stdout
    еще:
        вернуть False, answer.stdout+reply.stderr



parser = argparse.ArgumentParser(description='Сценарий проверки связи')

parser.add_argument('-a', action="store", dest="ip")
parser.add_argument('-c', action="store", dest="count", default=2, type=int)

аргументы = парсер.parse_args()
печать (аргументы)

rc, сообщение = ping_ip(args.ip, args.count)
распечатать (сообщение)
 

Создание парсера:

  • парсер = argparse.ArgumentParser(description='Ping script')

Добавление аргументов:

  • parser.add_argument('-a', action="store", dest="ip")
    • аргумент, который передается после -опция сохраняется в переменную ip
  • parser.add_argument('-c', action="store", dest="count", default=2, type=int)
    • аргумент, который передается после -c параметр будет сохранен в переменной считать , но сначала будет преобразовано в число.Если бы аргумента не было указано, по умолчанию 2

String args = parser.parse_args() указывается после того, как все аргументы были определены. После его запуска переменная args содержит все аргументы которые были переданы сценарию. Доступ к ним можно получить, используя синтаксис args.ip .

Давайте попробуем скрипт с другими аргументами. Если переданы оба аргумента:

 $ python ping_function.py -a 8.8.8.8 -c 5
Пространство имен (количество = 5, ip = '8.8.8.8')
PING 8.8.8.8 (8.8.8.8): 56 байт данных
64 байта из 8.8.8.8: icmp_seq=0 ttl=48 время=48,673 мс
64 байта из 8.8.8.8: icmp_seq=1 ttl=48 время=49,902 мс
64 байта из 8.8.8.8: icmp_seq=2 ttl=48 время=48,696 мс
64 байта из 8.8.8.8: icmp_seq=3 ttl=48 время=50,040 мс
64 байта из 8.8.8.8: icmp_seq=4 ttl=48 время=48,831 мс

--- 8.8.8.8 статистика пинга ---
5 пакетов передано, 5 пакетов получено, 0,0% потери пакетов
туда-обратно мин/средн/макс/стандартное отклонение = 48,673/49,228/50,040/0,610 мс

Пространство имен — это объект, который возвращает метод parse\_args().
 

Только пропуск IP-адрес:

 $ python ping_function.ру-а 8.8.8.8
Пространство имен (количество = 2, ip = '8.8.8.8')
PING 8.8.8.8 (8.8.8.8): 56 байт данных
64 байта из 8.8.8.8: icmp_seq=0 ttl=48 время=48,563 мс
64 байта из 8.8.8.8: icmp_seq=1 ttl=48 время=49,616 мс

--- 8.8.8.8 статистика пинга ---
2 пакета передано, 2 пакета получено, 0,0% потери пакетов
туда-обратно мин/средн/макс/стандартное отклонение = 48,563/49,090/49,616/0,526 мс
 

Сценарий вызова без аргументов:

 $ питон ping_function.py
Пространство имен (количество = 2, ip = нет)
Traceback (последний последний вызов):
  Файл "ping_function.py", строка 31, в 
    rc, сообщение = ping_ip(args.ip, args.count)
  Файл "ping_function.py", строка 16, в ping_ip
    стандартный вывод=темп)
  Файл "/usr/local/lib/python3.6/subprocess.py", строка 336, в check_output
    ````kwargs).stdout
  Файл "/usr/local/lib/python3.6/subprocess.py", строка 403, выполняется
    с Popen(*popenargs, ````kwargs) как процесс:
  Файл "/usr/local/lib/python3.6/subprocess.py", строка 707, в __init__
    restore_signals, start_new_session)
  Файл "/usr/local/lib/python3.6/subprocess.py", строка 1260, в _execute_child
    restore_signals, start_new_session, preexec_fn)
TypeError: ожидается объект str, bytes или os.PathLike, а не NoneType
 

Если функция была вызвана без аргументов, когда argparse не используется, возникнет ошибка, что не все аргументы указаны.

Из-за argparse аргумент фактически передается, но имеет значение None . Вы можете увидеть это в строке Namespace(count=2, ip=None) .

В таком сценарии всегда должен быть указан IP-адрес. И в argparse можно указать, что аргумент является обязательным. Сделать это, изменить - вариант : добавить обязательно = True в конце:

 parser.add_argument('-a', action="store", dest="ip", required=True)
 

Теперь, если вы вызовете скрипт без аргументов, вывод будет следующим:

 $ питон ping_function.py
использование: ping_function.py [-h] -a IP [-c COUNT]
ping_function.py: ошибка: требуются следующие аргументы: -a
 

Теперь вы видите четкое сообщение о том, что вам нужно указать обязательный аргумент и подсказка по использованию.

Кроме того, благодаря argparse доступна помощь :

 $ python ping_function.py -h
использование: ping_function.py [-h] -a IP [-c COUNT]

Пинг-скрипт

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти
  -а IP
  -c СЧИТАТЬ
 

Обратите внимание, что в сообщении все параметры находятся в разделе необязательных аргументов . argparse сам определяет, что параметры указаны, потому что они начинают с - и всего одной буквой в имени.

Установить IP-адрес в качестве позиционного аргумента (файл ping_function_ver2.py):

 подпроцесс импорта
из временного файла импорт TemporaryFile

импортировать аргументы


def ping_ip (ip_address, количество):
    '''
    Пингуем IP-адрес и возвращаем кортеж:
    В случае успеха: (код возврата = 0, вывод команды)
    При ошибке: (код возврата, вывод ошибки (stderr))
    '''
    ответ = subprocess.run(
        'ping -c {count} -n {ip}' .format(count=count, ip=ip_address),
        оболочка = Верно,
        стандартный вывод=подпроцесс.ТРУБКА,
        stderr=подпроцесс.PIPE,
        кодировка = 'utf-8',
    )
    если ответ.код возврата == 0:
        вернуть True, ответить.stdout
    еще:
        вернуть False, answer.stdout+reply.stderr



parser = argparse.ArgumentParser(description='Сценарий проверки связи')

parser.add_argument('хост', action="store", help="IP-адрес или имя для пинга")
parser.add_argument('-c', action="store", dest="count", default=2, type=int,
                    help="Количество пакетов")

аргументы = парсер.parse_args()
печать (аргументы)

rc, сообщение = ping_ip( args.хост, args.count )
распечатать (сообщение)
 

Теперь вместо опции -a вы можете просто передать IP-адрес. Он будет автоматически сохранен в переменной хоста . И это автоматически считается обязательным. То есть это уже не необходимо указать required=True и dest="ip" .

Кроме того, сценарий определяет сообщения, которые будут отображаться при вы звоните помощь . Теперь вызов скрипта выглядит так:

 $ python ping_function_ver2.ру 8.8.8.8 -с 2
Пространство имен (хост = '8.8.8.8', количество = 2)
PING 8.8.8.8 (8.8.8.8): 56 байт данных
64 байта из 8.8.8.8: icmp_seq=0 ttl=48 время=49,203 мс
64 байта из 8.8.8.8: icmp_seq=1 ttl=48 время=51,764 мс

--- 8.8.8.8 статистика пинга ---
2 пакета передано, 2 пакета получено, 0,0% потери пакетов
туда-обратно мин/средн/макс/стандартное отклонение = 49,203/50,484/51,764/1,280 мс
 

справка сообщение:

 $ python ping_function_ver2.py -h
использование: ping_function_ver2.py [-h] [-c COUNT] хост

Пинг-скрипт

позиционные аргументы:
  IP-адрес хоста или имя для пинга

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти
  -c COUNT Количество пакетов
 

Вложенные синтаксические анализаторы

Рассмотрим один из способов организации более сложной иерархии аргументов.

Файл parse_dhcp_snooping.py:

# --*- кодировка: utf-8 --*-
импортировать аргументы

# Значения по умолчанию:
DFLT_DB_NAME = 'dhcp_snooping.db'
DFLT_DB_SCHEMA = 'dhcp_snooping_schema.sql'


деф создать (аргументы):
    print("Создание БД {} со схемой БД {}".format((args.name, args.schema)))


определение добавить (аргументы):
    если args.sw_true:
        print("Добавление данных коммутатора в базу данных")
    еще:
        print("Чтение информации из файла(ов) \n{}".format(', '.join(args.filename)))
        print("\nДобавление данных в БД {}".формат (args.db_file))


деф получить (аргументы):
    если args.key и args.value:
        print("Получение данных из БД: {}".format(args.db_file))
        print("Запросить данные для хоста(ов) с {} {}".format((args.key, args.value)))
    Элиф args.key или args.value:
        print("Пожалуйста, укажите два или ноль аргументов\n")
        печать (show_subparser_help ('получить'))
    еще:
        print("Показ содержимого {}...".format(args.db_file))


синтаксический анализатор = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title='подкоманды',
                                   description='допустимые подкоманды',
                                   help='описание')


create_parser = подпарсеры.add_parser('create_db', help='создать новую базу данных')
create_parser.add_argument('-n', metavar='db-filename', dest='name',
                           default=DFLT_DB_NAME, help='имя файла БД')
create_parser.add_argument('-s', dest='schema', по умолчанию=DFLT_DB_SCHEMA,
                           help='имя файла схемы базы данных')
create_parser.set_defaults(func=создать)


add_parser = subparsers.add_parser('добавить', help='добавить данные в БД')
add_parser.add_argument('имя файла', nargs='+', help='файл(ы) для добавления в БД')
add_parser.add_argument('--db', dest='db_file', default=DFLT_DB_NAME, help='имя db')
add_parser.add_argument('-s', dest='sw_true', action='store_true',
                        help='добавьте данные переключателя, если они установлены, иначе добавьте обычные данные')
add_parser.set_defaults(func=добавить)


get_parser = subparsers.add_parser('get', help='получить данные из БД')
get_parser.add_argument('--db', dest='db_file', default=DFLT_DB_NAME, help='имя db')
get_parser.add_argument('-k', dest="ключ",
                        варианты=['mac', 'ip', 'vlan', 'интерфейс', 'коммутатор'],
                        help='ключ хоста (параметр) для поиска')
получить_парсер.add_argument('-v', dest="value", help='значение ключа')
get_parser.add_argument('-a', action='store_true', help='показать содержимое БД')
get_parser.set_defaults(func=получить)



если __name__ == '__main__':
    аргументы = парсер.parse_args()
    если не вары (аргументы):
        parser.print_usage()
    еще:
        args.func(аргументы)
 

Теперь создается не только парсер, как в предыдущем примере, но и вложенные парсеры. Вложенные парсеры будут отображаться как команды. Фактически они будут использоваться как обязательные аргументы.

С помощью вложенных парсеров создается иерархия аргументов и опций. Аргументы, добавляемые во вложенный парсер, будут доступны в качестве аргументов для этот парсер. Например, эта часть создает вложенный парсер create_db и добавляет -n вариант:

 create_parser = subparsers.add_parser('create_db', help='создать новую базу данных')
create_parser.add_argument('-n', назначение='имя', по умолчанию=DFLT_DB_NAME,
                           help='имя файла базы данных')
 

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

 create_parser = подпарсеры.add_parser('create_db', help='создать новую базу данных')
create_parser.add_argument('-n', metavar='db-filename', dest='name',
                           default=DFLT_DB_NAME, help='имя файла БД')
create_parser.add_argument('-s', dest='schema', по умолчанию=DFLT_DB_SCHEMA,
                           help='имя файла схемы базы данных')
create_parser.set_defaults(func=создать)
 

Метод add_argument добавляет аргумент. Здесь синтаксис точно такой же, как без вложенных парсеров.

Строка create_parser.set_defaults(func=create) указывает, что создает функция будет вызываться при вызове парсера create_parser .

Функция create получает в качестве аргумента все аргументы, которые были прошедший. И внутри функции вы можете получить доступ к необходимым аргументам:

 по умолчанию создать (аргументы):
    print("Создание БД {} со схемой БД {}".format(args.name, args.schema))
 

Если вы вызовете справку для этого скрипта, вывод:

 $ Python parse_dhcp_snooping.ру-ч
использование: parse_dhcp_snooping.py [-h] {create_db,add,get} ...

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти

подкоманды:
  допустимые подкоманды

  {create_db,добавить,получить} описание
    create_db создать новую базу данных
    добавить добавить данные в БД
    получить данные из БД
 

Обратите внимание, что каждый вложенный анализатор, созданный в сценарии, отображается как команда в подсказке по использованию:

Использование
: parse_dhcp_snooping.py [-h] {create_db,add,get} ...
 

Каждый вложенный анализатор теперь имеет свою собственную справку :

 $ Python parse_dhcp_snooping.py create_db -h
использование: parse_dhcp_snooping.py create_db [-h] [-n имя_базы_данных] [-s СХЕМА]

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти
  -n имя файла базы данных имя файла базы данных
  -s SCHEMA имя файла схемы базы данных
 

В дополнение к вложенным парсерам также есть несколько новых функций из argparse в этом примере.

нарги

Parser add_parser использует nargs :

 add_parser.add_argument('имя файла', nargs='+', help='файл(ы) для добавления в БД')
 

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

В этом случае сообщение help выглядит так:

 $ Python parse_dhcp_snooping.py добавить -h
использование: parse_dhcp_snooping.py добавить [-h] [--db DB_FILE] [-s]
                                  имя файла [имя файла ...]

позиционные аргументы:
  имя файла(ов) для добавления в БД

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти
  --db DB_FILE имя базы данных
  -s добавить данные переключения, если установлено, иначе добавить обычные данные
 

Если вы передадите несколько файлов, они будут в списке. И так как добавить функцию просто отображает имена файлов, вывод:

 $ python parse_dhcp_snooping.py добавить имя файла test1.текстовый файл test2.txt
Чтение информации из файла(ов)
имя файла, test1.txt, test2.txt

Добавление данных в БД dhcp_snooping.db
 

nargs поддерживает такие значения как:

  • N — указать количество аргументов. Аргументы будут в списке (даже если указан только один)
  • ? — 0 или 1 аргумент
  • * — все аргументы будут в списке
  • + — все аргументы будут в списке, но должен быть передан хотя бы один аргумент

на выбор

Parser get_parser использует вариантов :

 get_parser.add_argument('-k', dest="key",
                        варианты=['mac', 'ip', 'vlan', 'интерфейс', 'коммутатор'],
                        help='ключ хоста (параметр) для поиска')
 

Для некоторых аргументов важно, чтобы значение выбиралось только из определенных опции. В таких случаях вы можете указать вариантов .

Для этого парсера справка выглядит так:

 $ Python parse_dhcp_snooping.py получить -h
использование: parse_dhcp_snooping.py get [-h] [--db DB_FILE]
                                  [-k {mac,ip,vlan,интерфейс,коммутатор}]
                                  [-v ЗНАЧЕНИЕ] [-a]

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти
  --db DB_FILE имя базы данных
  -k {mac,ip,vlan,интерфейс,коммутатор}
                        ключ хоста (параметр) для поиска
  -v ЗНАЧ значение ключа
  -a показать содержимое БД
 

А если вы выбрали не тот вариант:

 $ Python parse_dhcp_snooping.py получить -k тест
использование: parse_dhcp_snooping.py get [-h] [--db DB_FILE]
                                  [-k {mac,ip,vlan,интерфейс,коммутатор}]
                                  [-v ЗНАЧЕНИЕ] [-a]
parse_dhcp_snooping.py получить: ошибка: аргумент -k: неверный выбор: «тест» (выбрать из «mac», «ip», «vlan», «интерфейс», «коммутатор»)
 

В этом примере важно указать разрешенные опции, которые можно было бы выбрать потому что на основе выбранной опции генерируется SQL-запрос. И благодаря варианты нет возможности указать недопустимый параметр.

Импорт парсера

В parse_dhcp_snooping.py последние две строки будут выполняться, только если скрипт был назван основным сценарием.

, если __name__ == '__main__':
    аргументы = парсер.parse_args()
    args.func(аргументы)
 

Поэтому при импорте файла эти строки вызываться не будут.

Попытка импортировать парсер в другой файл (файл call_pds.py):

 из парсера импорта parse_dhcp_snooping

аргументы = парсер.parse_args()
args.func(аргументы)
 

Звонок помощь сообщение:

 $ питон call_pds.ру-ч
использование: call_pds.py [-h] {create_db,add,get} ...

необязательные аргументы:
  -h, --help показать это справочное сообщение и выйти

подкоманды:
  допустимые подкоманды

  {create_db,добавить,получить} описание
    create_db создать новую базу данных
    добавить добавить данные в БД
    получить данные из БД
 

Вызов аргумента:

 $ Python call_pds.py добавить test.txt test2.txt
Чтение информации из файла(ов)
test.txt, test2.txt

Добавление данных в БД dhcp_snooping.db
 

Все работает без проблем.

Передача аргументов вручную

Последней возможностью argparse является возможность передавать аргументы вручную.

Аргументы могут быть переданы в виде списка при вызове метода parse_args (файл call_pds2.py):

 из парсера импорта parse_dhcp_snooping, получить

args = parser.parse_args('добавить test.txt test2.txt'.split())
args.func(аргументы)
 

Необходимо использовать метод split , так как метод parse_args ожидает список аргументов.

Результат будет таким же, как если бы скрипт был вызван с аргументами:

 $ Python call_pds2.py
Чтение информации из файла(ов)
test.txt, test2.txt

Добавление данных в БД dhcp_snooping.db
 

Подчеркивание в именах — Документация Python для сетевых инженеров 1.0

В Python символы подчеркивания в начале или в конце имени указывают на специальные названия. Чаще всего это просто аранжировка, но иногда фактически влияет на поведение объекта.

Подчеркивание в имени

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

Например, если вы хотите получить MAC-адрес, IP-адрес, VLAN и интерфейс из строки строки и отбросить остальные поля, вы можете использовать эту опцию:

 В [1]: строка = '00:09:BB:3D:D6:58 10.1.10.2 86250 dhcp-snooping 10 FastEthernet0/1'

В [2]: mac, ip, _, _, vlan, intf = line.split()

В [3]: print(mac, ip, vlan, intf)
00:09:BB:3D:D6:58 10.1.10.2 10 FastEthernet0/1
 

Эта запись указывает на то, что третий и четвертый элементы нам не нужны.

Вы можете сделать это:

 В [4]: ​​mac, ip, аренда, entry_type, vlan, intf = line.split()
 

Но тогда может быть непонятно, почему переменные лизинг и entry_type больше не используются. Лучше называть переменные такими именами, как , игнорируя .

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

 В [5]: [0 для _ в диапазоне (10)]
Выход[5]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 

Подчеркивание в интерпретаторе

В интерпретаторе python и ipython undesrcore используется для получения результата последнего эксперимента.

 В [6]: [0 для _ в диапазоне (10)]
Выход[6]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

В [7]: _
Выход[7]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

В [8]: а = _

В [9]: а
Выход[9]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
 

Одно подчеркивание перед именем

Один знак подчеркивания перед именем указывает, что это имя используется как внутреннее имя.

Например, если в имени функции или метода указано одно подчеркивание, это означает, что объект является внутренней реализацией и не должен использоваться напрямую.

Но также при импорте из модуля import * объекты, начинающиеся с подчеркивания, не будут импортированы.

Например, файл example.py содержит следующие переменные и функции:

 db_name = 'dhcp_snooping.db'
_path = '/home/nata/pyneng/'


функция защиты1 (аргумент):
    распечатать аргумент


защита _func2 (аргумент):
    распечатать аргумент
 

Если вы импортируете все объекты из модуля, те, которые начинаются с подчеркивания, не будут импортированы:

 В [7]: импорт из примера *

В [8]: db_name
Out[8]: 'dhcp_snooping.дБ'

В [9]: _path
...
NameError: имя '_path' не определено

В [10]: func1(1)
1

В [11]: _func2(1)
...
NameError: имя '_func2' не определено
 

Одно подчеркивание после имени

Одно подчеркивание после имени используется, когда имя объекта или параметра перекрывается с внедренными именами.

Пример:

 В [12]: строка = '00:09:BB:3D:D6:58 10.1.10.2 86250 dhcp-snooping 10 FastEthernet0/1'

В [13]: mac, ip, аренда, type_, vlan, intf = line.split()
 

Два символа подчеркивания перед именем

Два символа подчеркивания перед именем метода не используются просто как соглашение.Такой имена преобразуются в формат «имя класса + имя метода». Это позволяет создание уникальных методов и атрибутов классов.

Примечание

Это преобразование выполняется только в том случае, если менее двух окончаний подчеркивания или нет подчеркивания.

 В [14]: класс Switch(object):
    ...: __количество = 0
    ...: определение __configure(я):
    ...:         проходить
    ...:

В [15]: dir(Switch)
Исход[15]:
['_Switch__configure', '_Switch__quantity', ...]
 

Хотя методы были созданы без _Switch , он был добавлен.

Если вы создаете подкласс, то метод __configure не будет перезаписывать метод родительского класса Switch:

 В [16]: класс CiscoSwitch(Switch):
    ...: __количество = 0
    ...: определение __configure(я):
    ...:         проходить
    ...:

В [17]: каталог (CiscoSwitch)
Вышли[17]:
['_CiscoSwitch__configure', '_CiscoSwitch__quantity', '_Switch__configure', '_Switch__quantity', ...]
 

Два символа подчеркивания перед и после имени

Таким образом обозначаются специальные переменные и методы.

Например, модуль Python имеет такие специальные переменные:

  • __name__ — эта переменная равна __main__ при прямом запуске скрипта и равна имени модуля при импорте
  • __file__ — эта переменная равна имени скрипта, который был запущен напрямую, и равна полному пути к модулю при его импорте

__name__ переменная чаще всего используется для указания того, что определенная часть кода должна выполняться только тогда, когда модуль выполняется напрямую:

 по умножению (a, b):

    вернуть а * б

если __name__ == '__main__':
    печать (умножить (3, 5))
 

__file__ переменная может быть полезна при определении текущего пути к файлу скрипта:

 импорт ОС

печать('__файл__', __файл__)
печать (ос.path.abspath(__file__))
 

Вывод будет:

 __file__ example2.py
/home/vagrant/repos/tests/example2.py
 

Python также обозначает специальные методы таким образом. Эти методы вызываются при использовании функций и операторов Python и позволяют реализовать определенную функциональность.

Как правило, такие методы не нужно вызывать напрямую. Но, например, при создании собственного класса может потребоваться описание такого метода, чтобы объект поддерживал некоторые операции в Python.

Например, чтобы получить длину объекта, он должен поддерживать метод __len__ .

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

 В [10]: класс Switch(object):
    ...:
    ...: def set_name (я, имя):
    ...: self.name = имя
    ...:
    ...: определение __configure(я):
    ...:         проходить
    ...:
    ...: определение __str__(я):
    ...: вернуть 'Switch {}'.format(self.name)
    ...:

В [11]: sw1 = Switch()

В [12]: sw1.set_name('sw1')

В [13]: напечатайте sw1
Переключатель sw1

В [14]: ул(sw1)
Выход[14]: «Переключить sw1»
 

В Python есть много таких специальных методов. Несколько полезных ссылок, где можно прочитать о том или ином методе:

Python Scripts for Network Engineers » by CCIE #50038

Python Network Automation Script Examples

В этом руководстве по Python для сетевых инженеров я подробно расскажу о некоторых скриптах Python, которые сетевые инженеры могут начать использовать уже сегодня.Это скрипты, которые я использую почти ежедневно. К концу этого поста вы узнаете, что сетевые инженеры и Python действительно ладят!
Он прост в освоении и очень мощен.

Для каждого примера, требующего подключения, я буду использовать базовую топологию из 20 маршрутизаторов CSR.

Я также буду использовать Netmiko для подключения к сетевым устройствам. Если вы еще не использовали Netmiko, вы можете проверить это быстрое выполнение создания подключения к маршрутизатору Cisco с помощью Netmiko.

Если вам говорят, что вам нужно изучить код Python или внедрить сетевую автоматизацию, эти сценарии помогут вам начать работу.

Использование Python для автоматизации сети становится обязательным навыком в 2022 году. Поэтому вам необходимо убедиться, что вы понимаете свои объекты, переменные, методы, функции, словари и списки. Как один из самых популярных языков программирования, используемых сегодня, доступно так много информации, что приведенные ниже сценарии должны помочь вам начать работу.Программирование на Python — это навык, который будет очень полезен сетевым инженерам в 2022 году и далее.

Это лучший способ изучить Python

Если вы новичок в Python, вы можете ознакомиться с моим Учебным пособием по Python для начинающих

Если вы хотите загрузить все скрипты, используемые ниже, вы можете git клонировать репозиторий с помощью этой команды:
git clone https://github.com/rogerperkin/python-scripts-for-network-engineers.git

Примеры сценариев Python для сетевых инженеров

Все приведенные ниже примеры сценариев посвящены автоматизации сетевых устройств Cisco (в основном маршрутизаторов). ).Сценарии можно использовать и изменять по мере необходимости, и они будут работать на большинстве устройств, здесь они используются только на маршрутизаторах CSR в качестве лабораторного примера.

1. Сценарий Cisco Python для подключения SSH к маршрутизатору

Первый сценарий, который я покажу вам, — это подключение SSH к маршрутизатору.

Этот сценарий использует Netmiko для установления соединения, а затем я запускаю команду «show ip interface Brief» для проверки IP-интерфейсов на маршрутизаторе.

Скрипт на Github: ssh-to-router.py

 из netmiko import ConnectHandler

#Сначала создайте объект устройства с помощью словаря
КСО = {
    'тип_устройства': 'cisco_ios',
    «ИП»: «192.168.1.220',
    'имя пользователя': 'Роджер',
    'пароль': 'cisco'
}

# Далее устанавливаем SSH-соединение
net_connect = ConnectHandler (** CSR)

# Затем отправьте команду и распечатайте вывод
вывод = net_connect.send_command («показать краткий IP-адрес»)
печать (вывод)

# Окончательно закрыть соединение
net_connect.disconnect()
 

Это очень простой сценарий, который сначала импортирует из Netmiko ConnectHandler.

Примечание. Чтобы запустить это, вы должны сначала установить Netmiko — если у вас нет, посмотрите видео в верхней части этого поста.

Затем мы определяем устройство с именем CSR и предоставляем информацию, которую Netmiko требует, а именно тип_устройства , IP-адрес и имя пользователя и пароль .

Затем, используя модуль net_connect, вы подключаетесь к устройству CSR

После подключения мы отправляем команду «ship ip int Brief» на маршрутизатор и сохраняем значение в качестве вывода

Наконец, мы печатаем вывод и отключаемся от устройства.

2. SSH к нескольким маршрутизаторам

Теперь у нас есть базовое подключение к одному маршрутизатору, пришло время масштабировать его, теперь мы собираемся подключиться к 5 маршрутизаторам.Но это легко может быть 100 или 1000!

ssh-to-multiple-routers.py

Для этого я создал новый файл с именем devices.txt, который содержит все IP-адреса наших 5 маршрутизаторов CSR. Затем мы используем тот же сценарий, но проходим через соединение и передаем IP-адрес каждого маршрутизатора, чтобы мы могли получить вывод «sh ip int кратко» для всех маршрутизаторов.

 192.168.1.220
192.168.1.221
192.168.1.222
192.168.1.223
192.168.1.224
192.168.1.225
 

ПРИМЕЧАНИЕ: не нажимайте ввод в конце последней строки.В противном случае у вашего скрипта будут проблемы в конце.

 # SSH к нескольким устройствам из файла устройств
из netmiko импортировать ConnectHandler

с open('devices.txt') в качестве маршрутизаторов:
    для IP в роутерах:
        Маршрутизатор = {
            'тип_устройства': 'cisco_ios',
            'ip': IP,
            'имя пользователя': 'Роджер',
            'пароль': 'cisco'
        }

        net_connect = ConnectHandler (** Маршрутизатор)

        print('Подключение к' + IP)
        печать('-'*79)
        вывод = net_connect.send_command('sh ip int краткое')
        печать (вывод)
        Распечатать()
        печать('-'*79)

# Окончательно закрыть соединение
net_connect.disconnect()
 

Если вы делаете это в масштабе, вы должны использовать Python Automation Framework, например Nornir. Это дает вам преимущество инвентаризации, очень похожее на Ansible.

Тем не менее, все же полезно понять, как выполнить эту задачу вручную, прежде чем переходить к другим темам.

3. Сценарий Python для резервного копирования конфигурации Cisco

Теперь мы установили, как подключаться к нескольким устройствам и можем выполнять основные команды, следующим шагом будет возможность сохранить этот вывод.

Одной из первых задач, которую обычно выполняют люди, приступая к работе, является создание резервной копии файла конфигурации. Этот скрипт Python делает именно это.

backup-router.py

 из импорта netmiko ConnectHandler

#Сначала создайте объект устройства с помощью словаря
КСО = {
    'тип_устройства': 'cisco_ios',
    'ip': '192.168.1.220',
    'имя пользователя': 'Роджер',
    'пароль': 'cisco'
}

# Далее устанавливаем SSH-соединение
net_connect = ConnectHandler (** CSR)

# Узнайте имя хоста из подсказки

имя хоста = net_connect.send_command('показать запуск | я хост')
имя_хоста.split(" ")
имя_хоста,устройство = имя_хоста.split(" ")
print ("Резервное копирование" + устройство)

имя файла = '/home/roger/python-scripts-for-network-engineers/backups/' + устройство + '.txt'
# чтобы сохранить резервную копию в той же папке, что и скрипт, используйте строку ниже и закомментируйте строку выше
# имя файла = устройство + '.txt'

showrun = net_connect.send_command('show run')
showvlan = net_connect.send_command('показать vlan')
showver = net_connect.send_command('показать версию')
log_file = open(имя файла, "a") # в режиме добавления
журнальный файл.написать (показать)
log_file.write("\n")
log_file.write(showvlan)
log_file.write("\n")
log_file.write(показать)
log_file.write("\n")

# Окончательно закрыть соединение
net_connect.disconnect()
 

Примечание: вам нужно изменить имя файла = в соответствии с вашей средой

Продолжайте читать, чтобы узнать больше примеров сценариев Cisco Python.

4. Сценарий Python для резервного копирования нескольких маршрутизаторов

Теперь у нас есть сценарий, который может создавать резервные копии одного маршрутизатора Cisco. Очень просто взять сценарий, который мы использовали для подключения к нескольким маршрутизаторам, и просто добавить задачу резервного копирования в цикл for. .

Этот сценарий снова использует файл devices.txt для циклического просмотра списка IP-адресов и создания резервной копии каждого маршрутизатора.

Все резервные копии помещаются в /backups, но вы можете изменить расположение резервной копии, изменив путь после имени файла.

backup-multiple-routers.py

 # SSH к нескольким устройствам из файла устройств
из netmiko импортировать ConnectHandler

с open('devices.txt') в качестве маршрутизаторов:
    для IP в роутерах:
        Маршрутизатор = {
            'тип_устройства': 'cisco_ios',
            'ip': IP,
            'имя пользователя': 'Роджер',
            'пароль': 'cisco'
        }

        net_connect = ConnectHandler (** Маршрутизатор)

        имя хоста = net_connect.send_command('показать запуск | я хост')
        имя_хоста.split(" ")
        имя_хоста,устройство = имя_хоста.split(" ")
        print ("Резервное копирование" + устройство)

        имя файла = '/home/roger/python-scripts-for-network-engineers/backups/' + устройство + '.txt'
        # чтобы сохранить резервную копию в той же папке, что и скрипт, используйте строку ниже и закомментируйте строку выше
        # имя файла = устройство + '.txt'

        showrun = net_connect.send_command('show run')
        showvlan = net_connect.send_command('показать vlan')
        шоувер = net_connect.send_command('показать версию')
        log_file = open(имя файла, "a") # в режиме добавления
        log_file.write(showrun)
        log_file.write("\n")
        log_file.write(showvlan)
        log_file.write("\n")
        log_file.write(показать)
        log_file.write("\n")

# Окончательно закрыть соединение
net_connect.disconnect()
 

5. Генератор конфигурации с использованием Jinja2.

Jinja2 — это язык шаблонов для разработчиков Python. Он используется не только сетевыми инженерами, его можно использовать для создания файлов из шаблонов для любого кода Python.

Основная настройка заключается в том, что вы создаете файл шаблона, который содержит заполнители, где вы определяете значение, например DNS-сервер, затем у вас есть другой файл, содержащий эти значения, и когда вы запускаете свой скрипт Python, он выбирает значения и вставляет их в ваш шаблон и выводит готовый файл конфигурации, который вы можете отправить на свои сетевые устройства.

6. Проверка правильности IP

Этот простой сценарий Python использует модуль ipaddress и проверяет, является ли введенный адрес IPv4 или IPv6 действительным или нет.

 импорт ОС, IP-адрес

ОС.система('cls')

пока верно:
    ip = input('Введите IP-адрес:')
    пытаться:
        печать (ipaddress.ip_address (ip))
        print('IP действителен')
    Кроме:
        напечатать:('-' *50)
        print('IP недействителен')
    наконец:
        если ip == 'q':
           print('Сценарий завершен')
           перерыв
 

Эта страница находится в постоянном развитии, и поскольку я использую новый скрипт, я буду добавлять его сюда.

Если у вас есть какие-либо идеи для дополнительных примеров сценариев Python для сетевых инженеров, пожалуйста, напишите мне комментарий ниже.

Если вы хотите рассмотреть другие варианты, ознакомьтесь с моим списком лучших инструментов автоматизации сети

Темы для добавления:

netmiko, napalm, pyntc, telnet

Видео Python для автоматизации сети

Примечания для разработки

1 90 pathlib при открытии и записи в файлы
https://docs.python.org/3.9/library/pathlib.html

Другие сообщения Python

Курс Python для сетевых инженеров

Если вы хотите узнать больше об использовании Python Чтобы автоматизировать вашу сеть, в настоящее время я создаю онлайн-курс для сетевых инженеров, посвященный программированию на Python и тому, как использовать код Python для управления вашей сетью, больше информации здесь: Курс Python для сетевых инженеров

Если вам нужна дополнительная информация и вы хотели бы для предварительной регистрации – отправьте мне электронное письмо Контакт

Python для сетевых инженеров Книги

Использование Python для автоматизации сети – это навык, который сетевым инженерам в 2022 году нужно учиться.Вот некоторые из книг, которые я бы порекомендовал изучить в соответствии с вашим текущим знанием Python, начиная с начального уровня

Часто задаваемые вопросы

Нужны ли сетевому инженеру навыки программирования?

Короче говоря, ДА! Если вы хотите сделать карьеру сетевого инженера, вам придется освоить программирование до определенного уровня. Навыки программирования сегодня становятся все более важным навыком для сетевых инженеров. Поскольку большинство устройств предоставляют API, если вы хотите научиться программировать.Python — отличное место для начала.

Использует ли Cisco Python?

Cisco выбрала Python в качестве предпочтительного языка программирования для сетевых инженеров. Экзамен Cisco DevNet Associate проверяет опыт работы с Python и другими продуктами, такими как Meraki, Cisco ACI, — все они предоставляют API с хорошо документированной интеграцией сценариев Python.

Должны ли сетевые инженеры изучать Python?

Да, обязательно! Python позволяет создавать сценарии для автоматизации настройки сети.Это наиболее часто используемый язык программирования для автоматизации сетей, и сегодня он является критически важным навыком для сетевых инженеров.

Как изучить Python для работы в сети?

В Интернете доступно несколько курсов, позволяющих научиться использовать Python для работы в сети. Основная часть заключается в том, чтобы иметь возможность подключаться к устройствам по SSH, и для этого используется библиотека Netmiko, после чего вы можете пройти общий курс Python, а затем начать изучать Nornir.

Подходит ли Python для сетевых инженеров?

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

Подробнее о Python Network Automation

Курс обучения Python для сетевых инженеров

Программирование на Python теперь является обязательным навыком для сетевых инженеров. Я записал видео о себе, когда я изучал и практиковал программирование на Python.Я думаю, что эти видео, наряду со ссылками на учебные ресурсы, связанные с темой каждого видео, служат хорошим учебным пособием для сетевых инженеров, начинающих программировать на Python.

В этом посте собраны ссылки на все десять видео, которые я создал. В ходе этих видеороликов я написал программу под названием Usermapper , которая считывает файл конфигурации и создает XML-файл аутентификации для веб-прокси Guacamole. Я также использовал систему контроля версий Git и разместил код в моем репозитории Usermapper GitHub

.

Темы, которые мне нужно выучить

Много лет назад я немного изучил программирование во время обучения по программе «Электротехника».После того, как я получил высшее образование, кроме некоторых базовых скриптов, мне не приходилось заниматься никаким программированием.

Эти видеоролики не охватывают основы Python. Я настоятельно рекомендую вам прочитать книгу о Python или посмотреть обучающее видео (см. предложения ниже), прежде чем вы начнете работать с этими видео. Прежде чем я начал записывать это первое видео, я прочитал книгу О’Рейли Learning Python и написал сообщение в блоге о том, что я узнал из первой части книги.

Данное видео относится к следующим ресурсам:

Моя первая программа на Python

В этом видео я пишу первую часть программы, которая создаст файл аутентификации пользователя, совместимый с веб-прокси-сервером Apache Guacamole. Выходной файл в конечном итоге будет в формате XML, но эта первая версия создает словарь Python, заполненный всей необходимой информацией.

Когда я писал этот код, я узнал больше о модулях и пакетах, доступных в стандартной библиотеке Python.Я также получил хороший опыт работы с объектной моделью Python, поскольку она связана с копированием объектов и ссылок на объекты.

В этом видео я упоминаю следующие ресурсы:

Запись файла XML

В моем предыдущем видео я создал вложенный словарь, содержащий необработанные данные, которые должны быть записаны в формате XML в файл сопоставления пользователей. В этом видео я добавляю код, который записывает файл XML на основе содержимого этого словаря. Я решаю такие проблемы, как синтаксический анализ нескольких слоев вложенного словаря для изменения значений.

В этом видео я упоминаю следующие ресурсы:

Реорганизация моей программы

В этом видео я немного больше расскажу о Python, разбив свой текущий проект на функции и модули, чтобы упростить его обслуживание.

В настоящее время мой проект состоит из одного файла, и данные, используемые для создания выходного XML-файла, жестко запрограммированы в программе. Это не очень гибко и затрудняет использование программы другими.Сначала я разделю проект на файлы модулей, а потом часть логики программы превратю в функции.

В этом видео я упоминаю следующие ресурсы:

Git и GitHub

В этом видео я использую систему контроля версий Git для управления изменениями своего кода, а также создаю удаленный репозиторий на Github.

Перед просмотром этого видео рекомендую ознакомиться со следующим:

Другие ресурсы, которые я упоминаю в этом видео:

Виртуальные среды Python

В этом видео я начинаю делать свою первую программу более гибкой.Я определяю ввод в файле конфигурации. Я изучаю формат файла YAML. Я представляю виртуальные среды Python. Кроме того, я получаю больше практики в использовании Git, когда вношу изменения в свой код.

Перед просмотром этого видео рекомендую ознакомиться со следующим:

Другие ресурсы, которые я упоминаю в этом видео:

Перезапись

mapperdata.py

В этом видео я продолжаю делать свою первую программу более гибкой. Я использую виртуальную среду Python.Я устанавливаю пакет PyYAML , используя pip. Я переписываю свой модуль mapperdata.py для чтения конфигурационного файла YAML и построения структуры данных на основе его содержимого. Я делаю несколько классических ошибок при переборе вложенных словарей и добавляю полезную команду git restore.

Перед просмотром этого видео рекомендую ознакомиться со следующим:

Другие ресурсы, которые я упоминаю в этом видео:

Использование кода VS

В этом видео я заканчиваю переписывать свои мапперданные .py для чтения файла конфигурации YAML и построения структуры данных на основе его содержимого. Я также представляю текстовый редактор Visual Studio Code, который я буду использовать с этого момента.

Перед просмотром этого видео рекомендую просмотреть следующие короткие ролики:

Другие ресурсы, которые я упоминаю в этом видео:

Требования.txt и использование GitHub Issues

В этом видео я создаю требования .txt , чтобы другие могли легко развернуть приложение Usermapper. Я также исправить ошибку, которую я нашел в программе. Я использую GitHub Issues, чтобы сохранять заметки об улучшениях, которые я хотел бы внести в приложение, если найду время в будущем. Наконец, я обсуждаю, что, по моему мнению, потребуется, чтобы узнать достаточно о среде Flask, чтобы я мог перейти к следующему шагу.

Ресурсы, которые я упоминаю в этом видео:

Упаковка и аргументы командной строки

В этом видео я организую свои модули Python в пакет, который другие могут загрузить и установить.Я также модифицирую программу, чтобы пользователи могли указывать расположение и имена входных и выходных файлов в аргументах командной строки. Окончательный результат находится по адресу: https://github.com/blinklet/usermapper.git

.

Перед просмотром этого видео рекомендую прочитать следующую статью:

Другие ресурсы, которые я упоминаю в этом видео:

Заключение

В течение месяца я каждый вечер трачу около часа на изучение и практику Python.Я обнаружил, что выбор конкретного проекта для реализации на Python помог мне учиться. Если вы администрируете веб-прокси-сервер Guacamole, взгляните на мою программу Usermapper! Теперь я с нетерпением жду изучения среды Flask и создания веб-сайта с использованием Python.

Сетевое программирование на Python для сетевых инженеров (Python 3) —

Изучение сетевого программирования и сетевой автоматизации с использованием GNS3 и Python версии 3.

Этот курс основан на Python 3.

Хотите программировать сети с помощью Python, но не знаете, с чего начать? Что ж, этот курс покажет вам, как вы можете начать программировать сети Cisco в течение 20 минут.

Этот курс создан для сетевых инженеров. Существует слишком много других курсов Python, которые пытаются сделать сетевых инженеров разработчиками программного обеспечения. Вместо того, чтобы обучать автоматизации сети, они учат вас теории Python. Этот курс отличается.

Этот курс практический. Я не буду говорить о программировании в абстрактных терминах и заставлю вас ждать, прежде чем вы сможете начать автоматизировать сети. Я покажу вам, как можно быстро и легко начать сетевое программирование с помощью GNS3, Cisco IOS и Python.

Вы увидите демонстрации конфигурации маршрутизаторов и коммутаторов Cisco в GNS3. Например, как настроить несколько VLAN на нескольких коммутаторах или как настроить OSPF на маршрутизаторе и многое другое.

Этот курс показывает вам практические примеры использования Python для программной настройки сетевых устройств Cisco, а не просто рассказывает об этом.

Дни настройки сетей Cisco только с помощью интерфейса командной строки (CLI) подходят к концу.Вам необходимо добавить в свой набор навыков сетевое программирование с использованием Python и API.

Узнайте, как автоматизировать сети, используя:

– Телнет

— СШ

– Парамико

Нетмико

–  НАПАЛМ

Такие инструменты, как NAPALM и Netmiko, упрощают настройку и взаимодействие с сетевыми устройствами с помощью API, такого как NETCONF, или с помощью SSH. Не изобретайте велосипед. Используйте доступные вам инструменты, чтобы быстро и легко автоматизировать свои сети.

Некоторые комментарии к курсу:

«Знание материала только по первому видео сэкономило бы мне часы работы и переделок в прошлом».

«Это самый простой, интересный и ценный курс по программированию на Python для сетей, который я когда-либо проходил. Любить это! Еще раз спасибо Давид!!!”

«Отличный курс по сетевому программированию с использованием Python с большим количеством практических примеров настройки сети».

«Отличное объяснение.Красивое видео и вдохновляющие слова! Большое спасибо, Дэвид. Ты гений."

«Я уже давно занимаюсь сетевой автоматизацией, но тем не менее благодаря этому курсу я узнал много нового. Преподаватель начинает с простого примера, добавляя улучшения на каждом этапе. Это умение того стоит».

«Обязательно для всех сетевых инженеров, которые хотят изучать Python!!! У меня были очень «очень» базовые навыки программирования, и я не мог просто навести мост между сетью и программированием (в основном, Python — так как сейчас это ажиотаж), этот курс был потрясающим, я никогда не был приклеен к учебному курсу с тех пор Я могу вспомнить.Пара вещей, которые мне больше всего понравились в этом курсе: 1- Чистый голос Дэвида. 2- Применение в реальном мире. Дэвид не только представит различные практические модули из реального мира, которые вы можете импортировать и использовать, но и покажет вам, как применять их на устройствах iOS».

«Отличный курс по сетевому программированию с использованием Python с множеством практических примеров настройки сети. Качественный контент».

Курс Python для сетевых инженеров, обучение

(Все наши курсы имеют пожизненный доступ, поэтому вы не платите ежемесячные или ежегодные регулярные платежи, когда выходит новое обновление, вы получаете их бесплатно!)

Цена: 30 $ 19 $

Скидка 33%

Вам не нужно регистрироваться, чтобы получить доступ к нашим курсам!.Вы завершаете оплату, и мы автоматически отправляем электронное письмо с доступом.
КУПИТЬ СЕЙЧАС

О курсе Python для сетевых инженеров

Этот курс начинается с самых основ языка программирования Python. Он в основном ориентирован на сетевых инженеров. Наиболее часто используемые библиотеки сетевой автоматизации; такие как Netmiko, Napalm, Nornir, pyATS и Genie, объясняются, и многие практические лаборатории используются для демонстрационных целей.

Вы сможете выполнять лабораторные работы этого курса самостоятельно, просто следуя этому курсу.Это улучшит ваши знания Python и сетевой автоматизации, и вы сможете использовать эти инструменты даже в производственных сетях вашей компании.

Студенты помещаются в учебную группу с инструкторами, поэтому они сотрудничают, когда им это нужно!

Какова целевая аудитория для обучения сетевых инженеров?

    • Студенты, которые хотели бы начать разработку сетевых сред
    • Сетевые инженеры, желающие изучить основы Python с помощью практических занятий

Необходимые условия для курса Python

Для этого курса нет предварительных условий, вы просто должны хотеть учиться!

Для получения дополнительной информации [электронная почта защищена]

Пожалуйста, свяжитесь с [email protected] для групповых или корпоративных тренингов и любых других нетехнических тем.

Вы можете пройти курс прямо сейчас и сразу получить доступ ко всем ресурсам.

Курс

«Истории успеха для сетевых инженеров»


Сегодня я сдал #CCDE! Я использовал много ресурсов, чтобы добиться успеха, но мне нужно выделить один конкретный. Спасибо Орхану Эргуну за то, что он всегда был доступен в любое время, чтобы ответить на любой вопрос, обсудить каждую технологию и проработать мои личностные «проблемы», которые у меня были на протяжении всего этого процесса!! Для всех моих друзей, идущих по пути CCDE, Орхан — отличный ресурс и друг!

Майкл Зсига
Ведущий архитектор ePlus


Способность Орхана освещать обширные темы, необходимые для CCDE, огромна.Он не только очень техничен, но и потрясающий учитель.

Джейсон Гули

Системный инженер Cisco Systems


Я сдал практический экзамен CCDE, и курс Орхана CCDE был очень важным фактором моего успеха. Я посетил курс CCDE Орхана Эргуна в июле, и это было именно то, что мне было нужно, Орхан старается разобраться в различных технологиях.

Daniel Lardeux
Старший сетевой консультант в Post Telecom


После посещения курса CCDE Орхана Эргуна я сдал практический экзамен CCDE.Мне очень понравился курс. Прежде чем записаться, я не знал, чего ожидать, но это определенно отличный курс дизайна и подготовка к экзамену CCDE. В основном из-за взаимодействия с Орханом, который действительно является экспертом в объяснении всех различных технологий и создании из них идеальных дизайнов.

Рой Лексмонд

Старший сетевой дизайнер в Routez


Я сдал самый уважаемый экзамен Cisco CCDE в августе 2016 года. Я стал первым нигерийским CCDE, и CCDE Bootcamp Орхана Эргуна стал самым важным ресурсом в моем успехе.Если вы хотите зафиксировать CCDE, вам нужно мыслить как дизайнер. Вам нужно изменить свое мышление и понять все технологии в CCDE Blueprint. Ресурсы Орхана не могут быть даже сравнимы с любым провайдером обучения CCDE в отрасли. Я настоятельно рекомендую учебный лагерь Орхана CCDE всем, кто хочет сдать экзамены CCDE и понять дизайн сети в реальной жизни

Хаширу Амину
Услуги технического руководителя в Cisco Systems


Я записалась на тренинг Орхана CCDE.Этот тренинг очень технически подробен, а примеры использования, викторины, сценарии и интеллект-карты — все это отличные ресурсы в общей программе обучения. Орхан учит своих студентов думать как сетевой проектировщик, применяя технологии для удовлетворения бизнес-требований и проектных спецификаций.

Николас Руссо

Инженер-консультант по сетям (CCDE/CCIEx2), Cisco


Орхан заставляет вас снять шляпу реализации, которую большинство из нас носило в течение многих лет, вместо этого он предлагает шляпу нового причудливого дизайна, которая заставляет вас видеть и решать представленные проблемы.В начале этого курса CCDE вы много раз сидите и думаете: «Я мог бы решить эту проблему с помощью какого-нибудь хитрого трюка/функции», и все потому, что вы продолжаете думать о реализации. Однако по ходу курса Орхан помогает вам наполнить вашу новую причудливую дизайнерскую шляпу всей важной информацией не только для проектирования, удовлетворения бизнес-требований, но и для работы с протоколами взаимодействия. Если вы пытаетесь с головой окунуться в новую шапку, гонитесь за экзаменом CCDE или просто хотите стать лидером в проектировании сетей, я бы поехал к Орхану сегодня.

Андерс К. Петерсен

Инженер по сетевым системам, Conscia A/S CCIE


Я сдал экзамен CCDE 17 ноября 2016 года. Класс Орхана CCDE Live и самостоятельный учебный курс очень помогли мне сдать как письменный, так и практический экзамены CCDE. Таблицы сравнения дизайна и видео очень помогут вам на практическом экзамене CCDE. Тесты в рамках курса CCDE для самостоятельного обучения — отличный ресурс для письменного экзамена CCDE. Если вы готовитесь к экзамену CCDE или хотите изучить сетевое проектирование, я настоятельно рекомендую вам пройти этот курс.

Тахир Мунир
Консультант по инфраструктуре Accenture CCDE


Если вы планируете пройти обучение для получения желанной сертификации Cisco CCDE, хорошо используйте список рекомендуемой литературы Cisco и видеоролики CiscoLive, посвященные дизайну. Но ваша подготовка не будет полной без прикосновения Мидаса от главного тренера CCDE Орхана Эргуна. Он является наиболее полным поставщиком обучения в отрасли - книги, блоги, видео, учебные курсы, чат один на один и т. д. Курс самостоятельного обучения - лучший офлайн-ресурс CCDE!

Феликс Нкансах
Генеральный директор Red Mango

Роль Python Automation и навыков программирования в карьерном росте сетевого инженера

Роль автоматизации Python и навыков программирования в карьерном росте сетевого инженера

Python Automation and Programming изменили темпы карьерного роста сетевых инженеров.Многие из них думают, зачем нужен python для сетевых инженеров, когда у них есть другие люди для выполнения той же задачи. Когда в их организациях есть люди, которые выполняют всю работу по программированию, зачем им добавлять Python в свое резюме? Ответ: Python добавит ценность вашему резюме. Сетевому инженеру с Python отдается больше внимания, чем просто сетевому инженеру, и мы все знаем о конкурентном сценарии, через который мы проходим.

Скоро наступит время, когда такие языки программирования, как JAVA, C++ и Python, станут обязательными и обязательными.Зарплата быстро растет, и в некоторых городах за границей так много возможностей для Python.

Чем важен Python?

В этом динамичном мире, где все меняется с огромной скоростью, популярность Python, кажется, никогда не останавливается. Сегодня Python Certification является одним из самых востребованных навыков во всей области программирования. Но вы когда-нибудь представляли, действительно ли оно того стоит? Если да, то куда это может вас привести? Помимо этого, есть несколько других вопросов, которые могут вас беспокоить.В этой статье мы попытались ответить на все такие вопросы, касающиеся карьерных возможностей Python и того роста, который он дает сетевым инженерам.

Все, что им нужно было понять, это способ настройки сетевых устройств, как работать с маршрутизаторами и коммутаторами с помощью команд и т. д. Но теперь времена изменились. Сетевой инженер должен хорошо разбираться в написании кода в эпоху страстной конкуренции. Если он не знает, то считается, что он не поспевает за текущим сценарием, и понимание Python имеет решающее значение для вашего успеха в качестве сетевого инженера.

Вот пример обучающего видео для сетевых инженеров, чтобы научиться комментировать код Python с отраслевым экспертом:

Кроме того, он имеет множество библиотек, которые поддерживают анализ данных, визуализацию и манипулирование ими. Таким образом, он стал наиболее предпочтительным языком и считается « Next Big Thing » и « Принуждение » для профессионалов. Сегодня мы обсудим различные карьерные возможности Python, доступные для программиста Python.

Никогда не помешает выучить новый язык программирования. Если в вашей организации используется программно определяемая сеть (SDN), помните, что сети предоставляют интерфейсы для автоматического сканирования и мониторинга. Инструменты автоматизации, такие как Chef, могут выполнять часть рутинной работы, высвобождая время для ваших сетевых специалистов. Тем не менее, администраторы все равно должны понимать метод написания собственных скриптов. Независимо от того, используете ли вы Python, Java, Ruby или любой другой язык программирования, программирование становится все более важным для ИТ.

За что отвечает сетевой инженер?

Сетевой инженер — это технический специалист, который занимается контролем, проектированием, планированием и обслуживанием компьютерных сетей. Спрос на сетевого инженера быстро растет. Дополнительное значение имеет наличие у сетевого инженера навыков работы с Linux. Сетевому инженеру необходимо обновляться из-за внедрения новых технологий каждый день. За последние несколько лет наблюдается значительный рост программно-определяемых сетей.

Изучение Python будет очень полезно для сетевого инженера

Язык Python оказался одним из самых узнаваемых языков программирования последнего времени. Сетевые инженеры также могут выиграть от этого, этот талант наиболее востребован работодателями. Что ж, как вы уже поняли, кодирование имеет решающее значение для современных сетевых инженеров; однако сетевой инженер не собирается концентрироваться только на этом. Здесь на помощь приходит Python. Вам не нужно изучать сложные языки, такие как C++ или Java, но изучите Python и поднимите свою сетевую карьеру на новый уровень.

Это простой инструмент для управления и настройки серверов и задач. Python заключается в том, что вам требуется меньше кода, что является одним из основных преимуществ. Если вы являетесь начинающим ИТ-консультантом, сетевым инженером или сетевым консультантом, то вы многому научитесь после изучения Python.

Самая нижняя строка заключается в том, что сетевые инженеры также должны иметь навыки программирования, чтобы использовать новые инструменты, а также последнюю волну программирования.

Профили вакансий Python

  1. Сетевой инженер
  2. Разработчик Python
  3. Сетевой администратор
  4. Системный инженер
  5. Специалист по сетям
  6. Сетевой конструктор
  7. Инженер по сетевой безопасности
  8. Инженер-архитектор сети

Разработчик Python может:

  • Решение задач анализа данных
  • Создание веб-сайтов
  • Написание повторно используемого, тестируемого и эффективного кода
  • Алгоритмы оптимизации данных
  • Обеспечение безопасности и защиты данных

Вот некоторые из профилей работы, на которые человек может пойти после изучения Python.Как говорится, узнать что-то новое никогда не бывает потеряно.

Заключение

В настоящее время Python стал одним из самых важных курсов программирования для сетевых инженеров.

Post A Comment

Ваш адрес email не будет опубликован.