Даже в хорошей, с точки зрения дизайна, сети время от времени приходится проводить работы по актуализации конфигураций тех или иных сущностей. Среди наиболее веских и ожидаемых причин подобной активности можно отметить миграции для согласования физической и логической плоскостей, развитие сети в рамках процесса технологической эволюции, гармонизация архитектур присоединяемых сегментов и решение проблем роста. На самом деле, жизненный цикл сети, почти всегда представляет из себя изменения с тем или иным уровнем рисков и панируемого влияния на сервис, в оценке которого нельзя не учитывать человеческий фактор. Хотя, будет вполне уместным обобщить это описание на большинство областей человеческой деятельности, функционирование коммуникационных сетей обладает некоторыми особенностями, которые заслуживают понимания, или хотя бы внимания, — элементы коммуникационных сетей находятся в плотной связи, тесно взаимодействуют и оказывают не только прямое, но и косвенное воздействие друг на друга. Поэтому, грамотная стратегия проводимых работ станет только продуктивнее будучи подкреплённой механизмами, которые снижают, насколько это возможно, вероятность появления человеческих ошибок. В очередной статье цикла «Зачем сетевым инженерам программирование» я расскажу о вариантах применения автоматизации в одной задаче подобного рода.
Во многих «букварях» по сетевой архитектуре термины large-scale networks и hierarchical networks используются почти как синонимы, применительно к дизайну IGP домена обозначен простой и, на первый взгляд, понятный дизайн – дробление домена на области. При этом, порог насыщения – вещь сугубо индивидуальная, в каких-то случаях в одной IGP области может нормально сосуществовать тысяча современных маршрутизаторов, в ином случае и трехсот достаточно чтобы существенно снизить эксплуатационные характеристики. По большей части этот порог определяется наложенными на IGP протоколами, поэтому в условиях некоторой вариативности и неопределенности границ и масштабов будущей сети, «зубры» индустрии находят более гибким путь построения плоского домена с последующей миграцией его сформировавшихся частей в отдельные области. Иными словами, если вы не можете «сегодня смотреть в завтрашний день», стройте плоскую сеть и дробите ее по факту появления первых признаков деградации времени сходимости или излишней сложности эксплуатации, потому-как отсутствие иерархии все-таки лучше, чем неправильно выбранная в условиях неопределенности структура [1, 2, 3].
Довольно общих описаний и абстрактных примеров, предположим, что мы имеем дело с разросшейся областью OSPFv2 домена, топология физических волокон/каналов которого уже позволяет разглядеть в аморфной структуре границы будущих областей. Я не сторонник менять что-то по принципу «все или ничего», может так случится, что из-за непредвиденных обстоятельств пространство возможностей станет слишком узким, а ожидаемые риски слишком большими. Смена OSPFv2 области является деструктивной операцией, поэтому самая прямолинейная схема процесса миграции, которая заключается в последовательном переводе маршрутизаторов в новую область по пути от будущей границе вниз, удобна далеко во всех топологиях. К счастью, некоторое время назад в рекомендациях к развитию OSPF была обозначена возможность построения связности в рамках нескольких областей [4]. Пользуясь этой возможностью, мы можем разбить миграцию на три этапа:
На первом этапе топология новой области постепенно расширяется, на втором, топология старой области сужается. При соблюдении конгруэнтности топологий старой и новой областей, мы получим согласованную маршрутизацию между переведенными и не переведенными узлами, а это, в свою очередь, делает возможным деление этапов на независимые под-этапы, на каждом из которых работа может производится с некоторой частью узлов. К выбору узлов для работ в рамках под-этапа целесообразно подходить с точки зрения фактической утилизации каналов в конкретной сети, таким образом, чтобы не допускать перезагрузку на границе старой и новой областей. Несмотря на то, что статья посвящена программированию, думаю, не будет лишним сказать пару слов о поведении наложенных на 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».
Для наглядности я собрал в вот такую сеть на vMX.
vMX это полноценный программный маршрутизатор от Juniper Networks, во многом повторяющий поведение своего старшего, железного брата MX. Не то чтобы это был продукт, который нуждается в представлении, просто такие вещи полезно держать под рукой для упражнений в программировании или лабораторных испытаний. Триал, можно скачать тут «vMX Trial Download», а инструкцию по установке по этой ссылке «Preparing the System to Install vMX».
Маршрутизаторы bb, abr1 и abr2 образуют нулевую область, маршрутизаторы r1, r2, r3 и r4 – должны быть перемещены из 200-й области в 250-ю.
Применительно к маршрутизатору r2, будет сгенерирован следующий набор команд.
Как я уже писал элементы сети обладают внутренним состоянием, вокруг и внутри них что-то постоянно происходит независимо от того хотим мы этого или нет. Появление таких событий как отказ трансивера, отключение питания на узле или обрыв оптического канала нужно воспринимать как должное и учитывать при проведении работ. Я предлагаю обратить внимание на этот факт в контексте выбора проверок успешности этапов миграции. Как бы парадоксально это не звучало, в данном случае нам не обязательно проверять появилось ли OSPF соседство на том или ином интерфейсе, так как причины его отсутствия могут находится совсем в другой плоскости. Кроме перечисленного выше в исходные данные всегда может попасть ошибка или неточность, например, например, в виде всеми забытого интерфейса, который подлежит удалению, а в данный момент смотрит в «пустоту». В процессе формирования проверок полезно подняться на уровень выше, чтобы посмотреть на сеть с точки зрения оказываемых услуг и наложенных протоколов, так как в конечном счете состояние только этих вещей позволяет принять обоснованное решение об успешности того или иного этапа. Мало кто из заказчиков соглашается на публичные статьи по результатам выполненных работ, еще и поэтому я собрал виртуальную среду для демонстрации. В рамках этой среды я ограничусь проверкой состояния BGP сессий, которые построены по схеме каждый-с-каждым между маршрутизаторами, это и будет нашими наложенными сервисами, и услугами. Если, после работ выполняются условия для их работоспособности в виде IP связности каждый-с-каждым, значит есть и основания полагать что работы проведены успешно. В реальных проектах проверки обычно ограничиваются тем объемом услуг и наложенных протоколов, которые обозначается как business critical в данной сети. К программированию это не относится, тем не менее я не могу не заострить внимание на этом вопросе, так как выбор критерия успешности — это залог спокойного сна после проведенных работ.
До текущего момента мы беседовали по большей части о каких-то сетевых вещах, но я еще ни словом ни обмолвился о программном коде, который вроде как должен быть в центре внимания в статье с таким названием. Во-первых, мне кажется, что мысли намного важнее кода, формализовав сущности в голове инженер сможет превратить их в инструмент и изложить в виде кода. Во-вторых, мне не хочется повторятся, все что может показаться не очевидным в этих примерах, а также минимально необходимые знания для начала работы с Python и Pyez, содержатся в предыдущей статье цикла. В-третьих, код подготовки конфигурации осуществляет свою работу, что называется в офлайне и не оказывает мгновенного воздействия на сеть, поэтому вряд ли может вызвать какой-то интерес. Несколько иначе обстоят дела с кодом имплементации этапа исполнения, разработка этих процедур ставит перед нами следующие вопросы:
Чем больше внимания будет уделено этим вопросам, тем реже на этапе исполнения будут служатся неожиданности. Представьте каких хлопот может принести синтаксическая ошибка описания политики маршрутизации, когда классификаторы этой политики только частично одобрены интерпретатором. Если не проконтролировать построчно процесс слияния этой политики с текущей конфигураций можно одним нажатием клавиши перевести груду оборудования в неадекватное состояние. Поэтому, я придерживаюсь примерно такой блок схемы этапа исполнения.
Вооружившись документацией по Pyez был составлен следующий код универсального загрузчика конфигурации, который вы можете использовать в своей повседневной работе, так же как я использую его в своей.
И результаты его работы по трем этапам
Во многих «букварях» по сетевой архитектуре термины large-scale networks и hierarchical networks используются почти как синонимы, применительно к дизайну IGP домена обозначен простой и, на первый взгляд, понятный дизайн – дробление домена на области. При этом, порог насыщения – вещь сугубо индивидуальная, в каких-то случаях в одной IGP области может нормально сосуществовать тысяча современных маршрутизаторов, в ином случае и трехсот достаточно чтобы существенно снизить эксплуатационные характеристики. По большей части этот порог определяется наложенными на IGP протоколами, поэтому в условиях некоторой вариативности и неопределенности границ и масштабов будущей сети, «зубры» индустрии находят более гибким путь построения плоского домена с последующей миграцией его сформировавшихся частей в отдельные области. Иными словами, если вы не можете «сегодня смотреть в завтрашний день», стройте плоскую сеть и дробите ее по факту появления первых признаков деградации времени сходимости или излишней сложности эксплуатации, потому-как отсутствие иерархии все-таки лучше, чем неправильно выбранная в условиях неопределенности структура [1, 2, 3].
Довольно общих описаний и абстрактных примеров, предположим, что мы имеем дело с разросшейся областью OSPFv2 домена, топология физических волокон/каналов которого уже позволяет разглядеть в аморфной структуре границы будущих областей. Я не сторонник менять что-то по принципу «все или ничего», может так случится, что из-за непредвиденных обстоятельств пространство возможностей станет слишком узким, а ожидаемые риски слишком большими. Смена OSPFv2 области является деструктивной операцией, поэтому самая прямолинейная схема процесса миграции, которая заключается в последовательном переводе маршрутизаторов в новую область по пути от будущей границе вниз, удобна далеко во всех топологиях. К счастью, некоторое время назад в рекомендациях к развитию OSPF была обозначена возможность построения связности в рамках нескольких областей [4]. Пользуясь этой возможностью, мы можем разбить миграцию на три этапа:
- Построение дополнительной (secondary) связности в рамках новой области
- Перевод новой области в основной режим, а старой в дополнительный
- Удаление связности в рамках старой области
На первом этапе топология новой области постепенно расширяется, на втором, топология старой области сужается. При соблюдении конгруэнтности топологий старой и новой областей, мы получим согласованную маршрутизацию между переведенными и не переведенными узлами, а это, в свою очередь, делает возможным деление этапов на независимые под-этапы, на каждом из которых работа может производится с некоторой частью узлов. К выбору узлов для работ в рамках под-этапа целесообразно подходить с точки зрения фактической утилизации каналов в конкретной сети, таким образом, чтобы не допускать перезагрузку на границе старой и новой областей. Несмотря на то, что статья посвящена программированию, думаю, не будет лишним сказать пару слов о поведении наложенных на 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().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')
ospf_interfaces = OSPFInterface(ddev).get()
with open('st1-' + node + '.txt', "w") as f_st1:
for ospf_interface in ospf_interfaces:
if ( 'ge' in ospf_interface.name ):
f_st1.write('set protocols ospf area 0.0.0.250 interface ' + ospf_interface.name + ' secondary' + '\n')
f_st1.write('set protocols ospf area 0.0.0.250 interface ' + ospf_interface.name + ' interface-type p2p' + '\n')
f_st1.write('set protocols ospf area 0.0.0.250 interface ' + ospf_interface.name + ' metric ' + ospf_interface.cost + '\n')
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_interface.name + ' interface-type p2p' + '\n')
f_st1.write('set protocols ospf area 0.0.0.200 interface ' + ospf_interface.name + ' secondary' + '\n')
f_st1.write('set protocols ospf area 0.0.0.200 interface ' + ospf_interface.name + ' interface-type p2p' + '\n')
if (ospf_interface.cost != '0'):
f_st1.write('set protocols ospf area 0.0.0.250 interface ' + ospf_interface.name + ' metric ' + ospf_interface.cost + '\n')
f_st1.write('set protocols ospf area 0.0.0.200 interface ' + ospf_interface.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-ю.
lab@bb> 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;
}
}
}
lab@abr1> 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;
}
}
}
lab@abr2> 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;
}
}
}
lab@r1> 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;
}
}
}
lab@r2> 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;
}
interface lo0.0 {
interface-type p2p;
}
}
}
lab@r3> 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;
}
interface lo0.0 {
interface-type p2p;
}
}
}
lab@r4> 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;
}
interface 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
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.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!
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'}}
>>>
- The Complete IS-IS Routing Protocol — Hannes Gredler, Walter Goralski
- OSPF; Anatomy of an Internet Routing Protocol — John T. Moy
- Network Mergers and Migrations: Junos Design and Implementation — Gonzalo Gomez Herrero, Jan Anton Bernal Van Der Ven
- OSPF Multi-Area Adjacency — tools.ietf.org/html/rfc5185
mrobespierre
natenka.github.io/pyneng — всем тем, кто интересуется темой