Сценарии

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

Распишем каждый из них детально.

0. Проверка сети

Наверно, совершенно оправданным будет нулевой приоритет отдать именно блоку ручек для проверки сети, поскольку к ним нужно будет обращаться почти в каждом последующем сценарии.
Часть из них будут реализовывать blackbox-проверки. Например, наличие e2e-связности, потерь, RTT.
Другая - whitebox - существование тех или иных маршрутов в RIB, состояние FIB итд.
  1. Человек или сервис приходит в ручку NetAPI с запросом, в теле которого указаны параметры теста. Например, ICMP, устройство-источник, адрес назначения, VRF, число проб, размер пакета.
  2. NetAPI формирует запрос в NetGet, чтобы тот собрал данные с сети/устройства. И тот собирает.
  3. Результаты теста возвращаются клиенту.

1. Ввод нового оборудования

В зависимости от скорости роста, возможно, самый важный сценарий - быстро запускать новые узлы (стойки, филиалы, офисы), поскольку обычно занимает больше всего времени.

  1. Человек или часть системы, реализующей нечто а-ля ZTP, приходит в NetAPI для инициализации устройства.
    Устройство идентифицируется по своему серийнику или инвентарному номеру, и ему должна быть задана роль, чтобы было понятно, с какой конфигурацией его наливать.
    https://fs.linkmeup.ru/images/adsm/4/step1.svg
    1. Ручка дёргает конкретное приложение, отвечающее за этот шаг

    2. Приложение создаёт устройство в NetBox и прописывает его

      • Имя
      • Серийник
      • Локацию
      • Вендор/модель
      • Роль в сети
      • Присущие ему свойства: список интерфейсов, консольных портов, комментарии.
    3. Приложение определяет и при необходимости создаёт MGMT-интерфейс

    4. Приложение выделяет MGMT IP.

    На данном шаге устройство в минимальном виде заведено в инвентарной системе, и заполнены необходимые для первичной настройки параметры.
  2. Далее другая часть процесса, а-ля ZTP, приходит в ручку NetAPI в поисках первоначального конфига
    https://fs.linkmeup.ru/images/adsm/4/step2.svg
    1. Ручка дёргает конкретное приложение
    2. Приложение собирает данные из NetBox и, возможно, внешних систем
    3. Приложение рендерит конфиг, возвращает его клиенту и заодно складывает его в git-репозиторий.
    4. Клиент каким-то образом доставляет конфигурацию до устройства - это может быть ZTP или пропихивание конфига через консольный порт. Идентификатором устройства тут выступает серийник.
    После этого шага появляется удалённый SSH-доступ на устройство.
    Теперь по какому-то триггеру запускается конвейер ввода устройства в эксплуатацию.
    Триггером может быть:
    • Чьё-то ручное действие - например, нажатие кнопки в интерфейсе - и сигнал в NetAPI.
    • Обращение к ручке ввода в NetAPI от системы ZTP после завершения.
    • Факт появления доступа по SSH на устройство - например, кроняка пытается доступиться до железки, которая помечена как «для ввода».
  3. Заполняются данные в NetBox, которые в дальнейшем будут служить переменными для генерации конфигурации.

    https://fs.linkmeup.ru/images/adsm/4/step3.svg
    1. Система посылает в NetGet запрос на сбор данных о LLDP с данного свитча.

      1. Информация о соседях вносится в NetBox, порты связываются друг с другом.

      2. При необходимости создаются сабинтерфейсы или интерфейсы добавляются в LAG.

      3. Вычисляются (или выделяются) P2P IP-адреса.
        Необходимые изменения выполняются и на соседнем устройстве.
        Этот шаг позволяет, во-первых, подготовить данные для настройки IP-адресов, во-вторых, визуализировать топологию при необходимости, в-третьих, собрать в будущем информацию о BGP-соседях, если на узле используется BGP.
      4. Система создаёт набор виртуальных интерфейсов и выделяет IP-адреса. Например, loopback’и и VLAN-интерфейсы.

      5. Заполняет другие необходимые данные. Например, ASN, IS-IS Network Entity, настройки l2-интерфейсов.

  4. Обновление данных в NetBox инициирует запрос в NetAPI на запуск конвейера для вычисления и деплоя новой конфигурации. Это может быть, например, Web-hook, отправленный самим Netbox’ом.
    Речь здесь идёт обо всех устройствах, конфигурация которых меняется в результате ввода новых устройств. Добавляется новый Leaf - поменяется конфигурация Spine.
    https://fs.linkmeup.ru/images/adsm/4/step4-7.svg
  5. NetAPI через Диспетчера адресует задачу на ConfMan, который вычисляет вендор-агностик конфигурацию.
    Для этого система берёт формализованную модель конфигурации данных (питоновские объекты, yaml итд) и подставляет в неё данные из NetBox.
    Результатом может быть словарь, тот же yaml или питоновский объект.
  6. Система генерит конфиг для списка устройств. Результатом может быть текст, содержащий последовательность CLI-команд, NETCONF XML, набор объектов для YANG, Protobuf для gNMI.

  7. Выполняются лабораторные тесты CI/CD. Они могут быть в симуляторе, вроде Batfish, виртуальном стенде или всамделишной небольшой железной лабе, мимикрирующей под настоящую сеть.
    Даже для типовой операции, вроде описываемого ввода новых, серверов разумно их делать, ведь данные в SoT изменились - и выкатка может разломать сеть.
    Проходят ручные проверки и подтверждения.
    Это немного сколькзий момент. С одной стороны я всё же не верю, что в обозримом будущем на сеть новый конфиг можно катить без человеческого подтверждения, как это давно происходит в мире WEB-приложений.
    С другой - когда изменения катятся на тысячу устройств, пойди глазами всё просмотри. Поэтому всё же CI/CD и канареечные деплои - это то, к чему мы будем стремиться.
    Опционально этот шаг может выполняться в git-репозитории. Хотя заставлять человека переходить во внешний относительно основной системы автоматизации сервис - негуманно. Впрочем как первые шаги разработки такой системы - вполне нормально.

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

  8. По факту сгенерированного конфига или полученных апрувов формируется задача в Dispatcher для Carrier’а на доставку и применение конфигурации на сеть.

    https://fs.linkmeup.ru/images/adsm/4/step8-9.svg
  9. Диспетчер диспетчеризирует и следит за выполнением каждой конкретной задачи и всей транзакции целиком.
    Он несёт полную ответственность за то, когда выполняется задача и с каким статусом она завершается.
  10. В случае успешной транзакции Диспетчер обращается в ручки NetAPI, чтобы провести ряд тестов, проверяющих две вещи:
    • Новое устройство готово к обслуживанию трафика,

    • Сеть при этом не сломалась.

      https://fs.linkmeup.ru/images/adsm/4/step10-11.svg
    Запускаются какие-то пинги. Проверяется маршрутная информация на сети - сравнивается с бейзлайном (например, состояние, как было до деплоя). Последнее предполагает, что мы либо собрали состояние перед обновлением, либо есть некая база данных с временными рядами (TSDB - Time Series Data Base), содержащая срезы исторических данных.
    Есть тесты, падение которых вызовет аварию, но операция будет считаться завершённой. А есть те, после которых произойдёт автоматический откат всей транзакции. Лучше не сделать ничего, чем сделать хорошо, но наполовину.
  11. В случае успешных тестов в NetBox и/или иных системах проставляются индикаторы успешного ввода, новое устройство заводится в мониторинги и другие системы.

  12. С результатами Диспетчер идёт в ручку NetAPI и сообщает, что ввод завершён успешно, либо нет.

    https://fs.linkmeup.ru/images/adsm/4/step12.svg
Конвейер завершён.
Это весьма упрощённый конвейер, конечно. Здесь опущены шаги, которые могут быть фактически необходимы в реальной жизни: подавления аварийных сообщений, отписывание комментариев в тикеты, возможные проверки и подтверждения целевой конфигурации живыми людьми, всевозможные валидации на каждом шаге.

2. Переконфигурация из-за изменений переменных в инвентарной системе

Допустим по какой-то причине данные в нашем SoT поменялись - человек руками дескрипшон на порту изменил или автоматика пересчитала LLDP-соседства или ещё что-то.
Это изменение, которое должно привести к запуску конвейера по вычислению и выкатке новой конфигурации, описанного выше.

Триггером может быть Web-hook от SoT или опять же кроняка, которая следит за изменениями в этом SoT.

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

Не забываем про версионирование - изменения переменных в SoT фактически ведёт к изменению версии конфигурации сети. Мажорное, минорное или патч - это предмет жарких дискуссий, судьёй которому будет semver.

3. Переконфигурация из-за изменения дизайна

Это может быть как небольшое изменение политики маршрутизации или ACL, так и сравнительно масштабная вещь, такая как добавление нового типа сервиса на всю сеть.
В целом, что относить к дизайну, а что к переменным - вопрос не просто дискуссионный, думаю, он на данный момент не имеет точного ответа.
Так же вопрос без ответа, в каком виде дизайн должен храниться - питоновские объекты, словарь, yaml, json? Хотел бы знать.
Но допустим, что независимо от формы он хранится в гите. И тогда его изменение легко можно использовать как триггер для запуска конвейера для вычисления и деплоя новой конфигурации, который мы дважды уже тронули выше.
Впрочем, тут возможна специфика: изменения дизайна несут риски, поэтому неплохо бы добавить шаг проведения тестов в лабе с помощью CI/CD.

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

4. Сбор информации с устройств

В целом сбором информации занимается NetGet. Как периодическим, так и разовым по запросу.
Поэтому, когда нужно собрать, например, MAC’и с конкретного устройства, клиент идёт в ручку NetAPI, а тот в свою очередь дёргает NetGet.
NetGet формирует задачу для Диспетчера, чтобы Carrier сходил на устройство и собрал необходимую информацию.
Учитывая, что для таких запросов клиент ожидает синхронный режим, Диспетчер должен по возможности прогнать его с высоким приоритетом и быстро вернуть ответ NetGet’у.

Из любопытных идей для оптимизации: NetGet видится очень активноиспользуемым компонентом - вплоть до того, что мониторинг будет ходить в него, чтобы собрать счётчики и состояние сети - и, возможно, ему стоило бы держать открытыми и прогретыми сессии со всем флотом сетевых устройств. С использованием asyncio данные будут собираться просто в мгновение ока. А шардирование сетевых элементов по разным worker’ам позволит не упираться в лимиты.

5. Снятие и возврат нагрузки

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

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

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

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

  1. Клиент приходит в ручку NetAPI. А тот запускает конвейер увода нагрузки

  2. Приложение определяет список сервисов, которые нужно погасить (L2/L3VPN, базовая маршрутизация, MPLS итд)

  3. Приложение формирует список действий, которые нужно совершить.
    Например:
    1. Плавно увести трафик с помощью BGP gshut community или ISIS overload bit (или ещё чего-то
    2. Убедиться в отсутствии трафика на интерфейсах
    3. Выключить BGP-сессии в нужном порядке (сначала сервисные, потом транспортные
    4. Выключить интерфейсы
    5. Убедиться в отсутствии активных аварий по сервисам
  4. Зафиксировать статус задачи.

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

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

6. Обновление ПО

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

  2. Запускается конвейер снятия нагрузки

  3. Запускается конвейер обновления ПО:

    1. Залить файлы ПО
    2. Проверить контрольную сумму
    3. Обновить прошивку, указать загрузочные файлы, перезагрузить устройство и провести иные мероприятия
    4. После обновления проверить версию ПО
  4. Запустить конвейер возврата нагрузки.

7. Удаление устройства

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

  1. Клиент приходит в NetAPI. Тот дёргает приложение, отвечающее за удаление устройства.

  2. Приложение проверяет, что нагрузка на устройстве ниже определённого порога.

  3. Приложение обращается в NetAPI в ручку снятия нагрузки.

  4. Приложение ищет все зависящие от этого устройства объекты в SoT. Как пример:

    1. Интерфейсы
    2. IP-адреса
    3. Подсети
    4. Интерфейсы соседних устройств
    5. P2P-адреса соседних устройств
    6. Итд.
  5. Приложение удаляет их все.

  6. Изменения в SoT триггерят запуск уже известного нам конвейера. Как вы видите он весьма и весьма универсален.
    Как результат - настройки соседних устройств, относящиеся к удаляемому, так же удаляются в процессе деплоя новой конфигурации.
    Само же устройство затирается к заводским настройкам. Кроме того оно удаляется из всех мониторингов и других систем.
  7. Устройство удаляется из БД или помечается каким-то образом, если нужно сохранить о нём информацию.

8. Замена устройства

Случается, что свитч ломается. Или нужно железку проапгрейдить на новую модель. В общем надо её снять, а новую поставить.
Теоретически это выглядит как два шага:
  1. Удаление текущего устройства
  2. Добавление нового

Но нам важны несколько вещей:

  • Имя нового устройства должно быть таким же, как и у прежнего
  • Сохранить MGMT IP
  • Сохранить и другие атрибуты: лупбэки, вланы, ASN, итд
  • Скорее всего, и конфигурацию

Не факт, что это всё необходимо, но, скорее всего, так.

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

Поэтому я бы всё же рассматривал замену устройства на сети как

  • Удаление старого устройства
  • Добавление нового с определённым набором атрибутов, значение которых хотим зафиксировать, и которые в противном случае определялись/выделялись бы автоматически.
При этом процедура удаления, определённая шагом выше, берётся как есть: с удалением артефактов на других устройствах (пересоздадим на втором шаге) и вычисткой конфига с устройства (чтобы, например, оно случайно на новом месте неожиданно не запустилось со старыми адресами и не начало всасывать и блэкхолить трафик).
Естественно, сценарии этим не ограничиваются. Их количество, степень автоматизированности и результаты диктуются бизнес-логикой и рациональностью.

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

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