Программирование для сетевых инженеров: первый кейс
Использование программирования в сетевом деле уже стало трендом, поэтому в продолжении статьи Зачем сетевым инженерам программирование я начинаю серию небольших заметок про автоматизацию решения тех или иных практических задач. Чтобы развеять ореол сложности вокруг этой темы, будут опубликованы некоторые примеры и кейсы, в основном с использованием Python, и даны ссылки на более глубокий материал и техническую документацию. Вступительная статья этого цикла ниже.
Сначала пара слов для антагонистов, не спешите говорить «это не для меня». Тенденции, происходящие в индустрии сетей передачи данных, отодвигают вопрос «как сделать» на второй план, перемещая на первый план вопрос эффективной, т.е. безошибочной и не затратной, эксплуатации, эти же тенденции толкают нас, сетевых инженеров, к изучению различных средств автоматизации. Тем, чей разум не «заражен» вирусом под названием указатель на указатель на функцию, я предлагаю начать этот путь с Python, хорошим подспорьем в этом деле может послужить книга Automate the Boring Stuff with Python. Книга написана в очень дружественной для новичков форме, и прекрасно подойдет для получения необходимого минимума знаний и практического опыта. Материал глав, примеры и задания соответствуют духу и философии python:
- Красивое лучше, чем уродливое.
- Простое лучше, чем сложное.
- Сложное лучше, чем запутанное.
- Практичность важнее безупречности.
Итак, первый пример посвящен проверке operation состояний маршрутизатора Juniper Networks. В качестве опорной я выбрал задачу проверки наличия на удаленной стороне ответного плеча для сконфигурированных RSVP LSP. Наличие двустороннего MPLS транспорта является обязательным условием для передачи трафика различного рода VPN. Сервисная сигнализация вполне может работать по IP, а data-plane трафику необходимы бесшовные MPLS пути между PE маршрутизаторами. Для проверки LSP путей из CLI мы обычно используем команду
В данном случае нам требуется убедиться в том, что для каждой LSP из Ingress секции существует такая LSP из Egress секции, у которой адрес назначения равен адресу источника первой LSP.
Мы решим эту задачу с помощью Pyez, этот мини фреймворк содержит набор классов и структур данных для взаимодействия с маршрутизаторами из Python кода. Вот тут более детальное описание возможностей Understanding Junos PyEZ, и процедура установки Junos PyEZ
Pyez использует возможности Junos по преобразованию формата выводы в XML. Добавьте к любой команде опцию
и вы получите готовый интерфейс взаимодействия по каналу машина-машина. Более детально об этой возможности можно прочитать в XML and Junos OS Overview
Именно в таком виде Pyez получает данные с маршрутизатора, а так как мне не доставляет особенного удовольствия работа с сырыми XML данными, я расскажу как представления (View) и таблицы (Table) позволяют абстрагироваться от тонкостей этого формата.
Каждой команде Junos соответствует некоторый метод Pyez, чтобы узнать имя этого метода используйте опцию | display xml rpc . Имя метода находится прямо внутри тегов , в данном случае это get-mpls-lsp-information
user@host> show mpls lsp | display xml rpc ;
С форматом вывода методов и соответствующих им команд, можно ознакомится получив ответ в XML виде, или изучить его на страничке XML API Explorer — Operational Tags Применительно к команде get-mpls-lsp-information маршрутизатор ответит следующим образом:
. session-type count display-count up-count down-count detours . . destination-address is-detour source-address lsp-state lsp-pktbytes bypass-name no-statistics route-count rsb-count resv-style label-in label-out name mpls-p2mp-lsp-name p2mp-remerge-state lsp-description lsp-path-type mpls-lsp-type lsp-aggregation graceful-deletion-triggered source-tna-address destination-tna-address bidirectional associated-bidirectional lsp-associated-lspname lsp-associated-lspsrc upstream-label-in upstream-label-out suggested-label-in suggested-label-out recovery-label-in recovery-label-out psb-lifetime psb-creation-time path-mtu path-mtu-in-kernel sender-tspec . adspec ct-bw lsp-diffserv-info lsp-id tunnel-id proto-id p2mp-branch-id p2mp-subgroup-orig self-id p2mp-self-id session-id is-fastreroute is-linkprotection is-nodeprotection is-soft-preemption rsvp-path-status rsvp-lp-backup-route-cnt rsvp-lp-backup-lsp-cnt . . . . . . . . . . . destination-address source-address lsp-state route-count active-path is-primary name bidirectional associated-bidirectional lsp-associated-lspname lsp-associated-lspsrc lsp-description lsp-pktbytes lsp-packets lsp-bytes aggregate-lsp-pktbytes no-statistics mpls-p2mp-name lsp-type lsp-control-status egress-label-operation is-fastreroute is-linkprotection is-nodeprotection is-inter-domain-path load-balance lsp-diffserv-te-info metric revert-timer revert-timer-remain optimize-protection-timer . . . lsp-creation-time lsp-soft-preemption-counter lsp-soft-preemption-time retry-timer retry-limit . . .
XML документ состоит из элементов, которые могу содержать дочерние элементы или атомарные значения. Например, элемент содержит дочерние элементы , которые в свою очередь содержат элементы , внутри которых есть элемент с атомарными значениями типа name .
Чтобы организовать цикл по вложенным структурам такого рода, я использую представления и таблицы. Этот подход опирается на динамическую типизацию Python для создания массивов или списков словарей на этапе выполнения. Если элемент, например , содержит некоторое количество под-элементов , вы получите их список, а если под-элемент, например уникален, вы получите его значение в виде объекта. Более детально о таблицах и представлениях написано в Defining Junos PyEZ Operational Tables и в Defining Junos PyEZ Views for Operational Tables.
Заполнение формата представлений и таблиц в коде примера осуществляется в строковой переменной yml , ключевые элементы этого формата ниже:
Значение rpc используется в таблице, и содержит имя метода из display xml rpc вывода.
Значение item используется в таблице, и содержит имя элемента XML, который нас интересует. Имена задаются с учетом иерархии пути в XML документе.
Значение view используется в таблице, и содержит описание представления. В случае наличия вложенных элементов, вы должны сделать вложенные описания.
Значение fields используется в представлении и содержит имена атомарных элементов.
Вот, пожалуй, все, что нужно знать о Pyez для организации итерации по плоским и вложенным operational данным маршрутизатора, завершенный пример ниже.
import sys import yaml from jnpr.junos.factory.factory_loader import FactoryLoader from jnpr.junos import Device yml = ''' --- MplsSession: rpc: get-mpls-lsp-information item: rsvp-session-data view: MplsSessionView MplsSessionView: fields: type: session-type count: count lsp: _MplsLsp rsvp: _RsvpLsp _RsvpLsp: item: rsvp-session view: _MplsLspView _MplsLsp: item: rsvp-session/mpls-lsp view: _MplsLspView _MplsLspView: fields: dst_addr: destination-address src_addr: source-address state: lsp-state route_count: route-count active_path: active-path name: name ''' globals().update(FactoryLoader().load(yaml.load(yml))) if (len(sys.argv) < 4): print 'Call this script as ' + sys.argv[0] + ' host user password ' sys.exit() try: host = sys.argv[1] user = sys.argv[2] password = sys.argv[3] dev = Device(host=host, user=user, password=password, mode='telnet', port='23') dev.open() except Exception: print 'Cannot connect to ' + host sys.exit() bt = MplsSession(dev).get() dev.close() out='' for s in bt: if (s.type == 'Ingress'): for l in s.lsp: bidir = 0 for ss in bt: if (ss.type == 'Egress'): for r in ss.rsvp: if ( (r.dst_addr == l.src_addr) and (r.src_addr == l.dst_addr) ): bidir = 1 out = 'Remote LSP named ' + r.name if (bidir == 0): print 'Unidirectional LSP named ' + l.name + ' to: ' + l.dst_addr + ' is in ' + l.state + ' state' if (bidir == 1): print 'Bidirectional LSP named ' + l.name + ' to: ' + l.dst_addr + ' is in ' + l.state + ' state' print out print ''
О книге#
Если «в двух словах», то это такой CCNA по Python. С одной стороны, книга достаточно базовая, чтобы её мог одолеть любой желающий, а с другой стороны, в книге рассматриваются все основные темы, которые позволят дальше расти самостоятельно. Книга не ставит своей целью глубокое рассмотрение Python. Задача книги – объяснить понятным языком основы Python и дать понимание необходимых инструментов для его практического использования. Всё, что рассматривается в книге, ориентировано на сетевое оборудование и работу с ним. Это даёт возможность сразу использовать в работе сетевого инженера то, что было изучено на курсе. Все примеры показываются на примере оборудования Cisco, но, конечно же, они применимы и для любого другого оборудования.
Для кого эта книга#
Для сетевых инженеров с опытом программирования и без. Все примеры и домашние задания будут построены с уклоном на сетевое оборудование. Эта книга будет полезна сетевым инженерам, которые хотят автоматизировать задачи, с которыми сталкиваются каждый день и хотели заняться программированием, но не знали, с какой стороны подойти.
Ещё не решили, нужно ли читать книгу? Почитайте отзывы .
Зачем Вам учиться программировать?#
Знание программирования для сетевого инженера сравнимо со знанием английского. Если вы знаете английский хотя бы на уровне, который позволяет читать техническую документацию, вы сразу же расширяете свои возможности:
- доступно в несколько раз больше литературы, форумов и блогов;
- практически для любого вопроса или проблемы достаточно быстро находится решение, если вы ввели запрос в Google.
Знание программирования в этом очень похоже. Если вы знаете, например, Python хотя бы на базовом уровне, вы уже открываете массу новых возможностей для себя. Аналогия с английским подходит ещё и потому, что можно работать сетевым инженером и быть хорошим специалистом без знания английского. Английский просто даёт возможности, но он не является обязательным требованием.
Требуемые версии ОС и Python#
Все примеры и выводы терминала в книге показываются на Debian Linux. В книге используется Python 3.7, но для большинства примеров подойдет и Python 3.x. Только в некоторых примерах требуется версия 3.6 или выше чем 3.5. Это всегда явно указано и, как правило, касается дополнительных возможностей.
Примеры#
Все примеры, которые используются в книге, располагаются в репозитории. Примеры, которые рассматриваются в разделах книги, являются обучающими. Это значит, что они не обязательно показывают лучший вариант решения задачи, так как они основаны только на той информации, которая рассматривалась в предыдущих главах книги. Кроме того, довольно часто примеры, которые давались в разделах, развиваются в заданиях. То есть, в заданиях вам нужно будет сделать лучшую, более универсальную, и, в целом, более правильную версию кода. Если есть возможность, лучше набирать код, который используется в книге, самостоятельно, или, как минимум, скачать примеры и попробовать что-то в них изменить – так информация будет лучше запоминаться. Если такой возможности нет, например, когда вы читаете книгу в дороге, лучше повторить примеры самостоятельно позже. В любом случае, обязательно нужно делать задания вручную.
Задания#
Все задания и вспомогательные файлы можно скачать в репозитории, том же, где располагаются примеры кода. Если в заданиях раздела есть задания с буквами (например, 5.2a), то нужно выполнить сначала задания без букв, а затем с буквами. Задания с буквами, как правило, немного сложнее заданий без букв и развивают идею в соответствующем задании без буквы. Если получается, лучше делать задания по порядку. В книге специально не приведены ответы на задания, так как, к сожалению, когда есть ответы, очень часто вместо того, чтобы попытаться решить сложное задание самостоятельно, подглядывают в них. Конечно, иногда возникает ситуация, когда никак не получается решить задание – попробуйте отложить его, задать вопрос в Slack и сделать какое-либо другое.
На Stack Overflow есть ответы практически на любые вопросы. Так что, если Google отправил Вас на него, это, с большой вероятностью значит, что ответ найден. Запросы, конечно же, лучше писать на английском – по Python очень много материалов и, как правило, подсказку найти легко
Ответы могли бы показать, как ещё можно выполнить задание или же как лучше это сделать. Но на этот счёт не следует переживать, так как, скорее всего, в следующих разделах встретится пример, в котором будет показано, как писать такой код.
Вопросы#
Для части тем книги созданы вопросы:
Эти вопросы можно использовать как для проверки знаний, так и в роли заданий. Очень полезно поотвечать на вопросы после прочтения соответствующей темы. Они позволят вам вспомнить материал темы, а также увидеть на практике разные аспекты работы с Python. Постарайтесь сначала ответить самостоятельно, а затем подсмотреть ответы в IPython по тем вопросам, в которых вы сомневаетесь.
Презентации#
Для всех тем книги есть презентации в репозитории. По ним удобно быстро просматривать информацию и повторять. Если вы знаете основы Python, то стоит их пролистать.
Форматы файлов книги#
Книгу можно скачать в двух форматах: PDF, Epub. Они автоматически обновляются, поэтому всегда содержат одинаковую информацию.
Обсуждение#
Для обсуждения книги, заданий, а также связанных вопросов используется Slack. Все вопросы, предложения и замечания по книге также пишите в Slack.