Когда Wi-Fi только появился на первых линиях метро, мы поняли, что превращаемся в героя Билла Мюррея из «Дня сурка». С той лишь разницей, что он каждый раз просыпался 2 февраля, а мы неделями пытались поймать поезда хотя бы одной ветки и залить на них одну и ту же конфигурацию. Настраивать ее вручную было плохой идеей — поезда уходили в депо и стояли там несколько дней.
Доктор, это лечится?
Мы поняли, что без автоматического инструмента вся компания будет только и делать, что ловить проблемные поезда и заливать конфигурации. Большая часть нашего оборудования от Cisco, и сначала мы хотели найти существующее решение вендора. Попробовали настроить систему Cisco Prime, но позже отказались от нее по нескольким причинам:
1) дорогие лицензии на такое количество оборудования, как у нас, — более 10 тыс. единиц;
2) не поддерживалось установленное на поездах оборудование RADWIN;
3) стандартные проблемы, связанные со спецификой нашей сети.
Мы пробовали и другие варианты, но в августе 2014 года вышло одно Постановление Правительства, и тогда уже точно нужно было менять подход. Предстояло полностью изменить конфигурацию контроллеров поездных составов, чтобы запустить систему обязательной идентификации.
Тогда у нас уже был отдел разработки ПО. Почему бы не реализовать необходимую функциональность самим? Нужен сервис, который круглосуточно пытается подключиться к оборудованию до тех пор, пока не «зальет» на него скрипт с конфигурацией. Ни версионности, ни эталонной конфигурации. Только выполнение конкретного маленького скрипта.
Внесите в протокол: telnet/ssh и нюансы в восприятии команд
Оказалось, что курсы CCNA я проходил не зря. Благодаря им я знал, как настраивать оборудование Cisco. Кроме того, у меня был опыт разработки отдельных сервисов, которые «общались» с другими приложениями через консоль.
Дело техники
Оборудование составов поездов управляется через консоль с помощью стандартных протоколов telnet и SSH. Часть оборудования поддерживает мониторинг и управление через SNMP. Отдельные единицы оборудования плохо доступны со стационарной сети из-за особенностей сетевого уровня, поэтому добраться до них можно только через головное оборудование, используя CDP
Времени на поиск идеального решения не было, и мы остановились на самом простом: автоматизировать то, что вручную вводит оператор через консоль.
Это общая схема:
Казалось бы, решение простое, проблем быть не должно, но нет. На его работу повлияла специфика отдельных типов оборудования.
Дело техники
Для универсальности выбрали протокол telnet/SSH, однако в нем нельзя точно понять, когда устройство закончит “писать” ответ и будет ожидать ввода от пользователя. Чтобы решить эту проблему, мы создали собственный словарь “стоп-символов”. У каждой команды, которая отправлялась в консоль, было несколько атрибутов: эхо, тайм-аут ответа и признак завершения ответа. По ним определялось поведение сервиса после отправки команды. Признаком завершения был спецсимвол, идущий после названия устройства в консоли: “>” или “#”
Летим на Базу!
В основе любой системы управления конфигурациями должна быть база данных соответствующего оборудования. Так как мы не использовали стандартные решения для инвентаризации, то решили сформировать структуру данных на основе понятной нам структуры метро:
1) оборудование находится в вагонах со своим типом и номером;
2) поезда часто пересобирают из разных вагонов, поэтому мета-сущность поезда актуальна, только если он находится на линии, а, значит, на связи;
3) поезда ходят по линиям — в Москве их 13;
4) оборудование бывает разных типов и имеет разные настройки.
Кроме этого, мы придумали «виртуальные» поезда, и привязали к ним стационарное оборудование: базовые станции в тоннеле, оборудование станционных узлов и сетевых ядер.
Все по плану
Систему конфигурирования мы решили реализовать через планировщик. В отдельной таблице задаются скрипты, которые нужно применить. Они хранятся целиком, как есть, со всеми спецсимволами и атрибутами. Чтобы упростить выборку, мы привязали скрипты к типу оборудования и добавили признак наследования.
Однако при настройке поезда целиком появляется зависимость между разными типами оборудования: так, чтобы не потерять доступность контроллеров при смене адресации, сначала нужно было настраивать поездные роутеры и только потом – контроллеры. У скриптов мы добавили признак активности и критерий “применять, только если оборудование на связи”. Здесь же решили на уровне логики сервиса обновлять параметр доступности оборудования при соединении с заданным IP-адресом.
Далее мы ввели таблицу задач, которые ссылались на скрипты и также имели признак активности и поле параметров. Ключевой из них – текст SQL-запроса на выборку идентификаторов устройств, на которые надо отправить конфигурацию. Использование именно такой схемы позволяло по любым признакам выбирать устройства из базы для конфигурирования выбранным скриптом.
Наконец, мы создали таблицы событий и исполняемых в настоящее время задач. События ссылались на задачи, а также имели атрибуты наследования. Можно было задать, какое следующее событие нужно исполнить в случае успеха или в случае ошибки, а также поля последнего срабатывания события и заданной периодичности. Некоторые события должны были вызываться по времени, а другие только как следствие, поэтому мы ввели расширенную типизацию, совместив это поле с признаком неактивности. В таблице текущих задач были записаны связки из идентификаторов оборудования, события и задачи, а также время последнего исполнения и атрибуты статуса.
Крючок для поездов
После того как структуру данных спроектировали, и общая модель реализации стала понятна, я написал программу для выполнения задач. Это было двухпоточное решение: один поток проверял активные события в базе и создавал или менял соответствующие записи в таблице активных задач. Второй последовательно проходил все активные задачи и пытался их исполнить. Так появилась первая версия системы.
Дело техники
Весь сервис я написал в среде Embarcadero RAD Studio версии 2010 с использованием компонентов Overbyte ICS и Devart Unidac и SecureBridge. Первоначально это был системный сервис под MS Windows, его конфигурация хранилась в отдельном файле в формате XML.
Главным недостатком конфигурации была скорость работы: большая часть оборудования была не на связи. Кроме того, из-за особенностей строения подсети управления, связь с оборудованием занимала несколько секунд. Мы задавали тайм-аут подключения от 30 секунд до 2 минут, и за сутки удавалось поймать максимум 20 поездов.
Очевидно, что ключ к повышению производительности – многопоточность. Опустим все сложности, с которыми я столкнулся при разработке многопоточного решения (кто пробовал делать нечто подобное под Windows, знают об этом не понаслышке). Желаемого результата мы достигли, и на виртуальной машине в 6 ядер сервис мог одновременно обрабатывать более 500 единиц оборудования.
Следующим шагом оптимизации стало выделение «легкой» задачи проверки доступности оборудования. Я написал отдельный запрос для всех типов “поездного” оборудования и задал периодичность раз в 30 минут. За это время либо один поезд уходит с линии, либо приходит новый. Включив соответствующий критерий в других задачах, я добился того, что опрашивались только единицы оборудования, которые находились на связи за последние полчаса. И в таком режиме мы продержались достаточно долго, пока не столкнулись с нюансами уже на уровне эксплуатации.
Дело техники
Не раз я порывался заняться перекомпиляцией сервиса под Linux-подобную ОС. Правда, эту задачу я так и не решил, т.к. в ней не было реальной потребности. Голая “виртуалка” на базе Windows Server 2012 только с этим сервисом и отдельно стоящая “виртуалка” с БД на базе MariaDB под CentOS 6 работали настолько устойчиво, что не было смысла тратить время на подобное улучшение.
Эксплуатация, бессердечная ты… мука
За несколько лет существования сети мы создали и применили более 160 скриптов: у многих из них были сложные зависимости и необходимость последовательного применения на одном и том же оборудовании. В основном настраивали Access-List-ы и меняли правила QoS, но были и критические изменения, связанные с авторизацией и DHCP.
В итоге, из-за недостатков системы конфигурирования, поезда ездили с оборудованием, настроенным совершенно по-разному. Пользователи вполне могли попасть в поезда, где Wi-Fi не работал только потому, что устройства были некорректно настроены. В большинстве случаев ситуацию оперативно исправляли, но шквал заявок в службу поддержки по выявленной проблеме, оставлял неизгладимый след.
Другие проблемы были связаны с заменой физически неисправного оборудования. Эксплуатация меняла оборудование на новое с настройками “по умолчанию”, которые могли быть уже несовместимы с актуальной системой предоставления сервиса. Автоконфигуратор не исправлял подобные ошибки, т.к. считал, что оборудование настроено корректно. Со временем это стало существенной проблемой: пользователи могли ехать в поездах без Wi-Fi только по этой причине. Решением стала передача множества скриптов и правил в эксплуатацию, но человеческий фактор никто не отменял, и ошибки хоть и стали возникать реже, выявлялись все так же мучительно и долго.
Система СИ: общие требования к конфигурации, маркер версии на оборудовании
Тогда мы придумали “эталонный скрипт”, который приводит конфигурацию оборудования в нужное нам состояние. И для полного счастья нужно было придумать способ, сохраняющий метку конфигурации прямо на оборудовании. Для контроллеров мы стали использовать пустые ACL-и. Например, для версии от 1 января 2015 года мы создали ACL с именем «v2015010101» – этот параметр легко считать, а реализованное хранение логов применения скриптов прямо в базе позволило строить запросы на основании информации, собранной с оборудования сервисными скриптами. Итоговая схема конфигурирования стала такой:
Дело техники
Для роутеров в качестве маркера мы стали использовать пустую директорию на флеше. В целом, общая структура скрипта выглядит примерно так:
sh flash:
… проверяем результат на предмет наличия маркера актуальной конфигурации, если маркера нет, идем дальше…
delete /recursive /force flash:v2016071001
delete /recursive /force flash:v2016101001
… тут удаляются все старые маркеры…
delete /recursive /force flash:v2016111101
conf t
… далее идет основной код конфигурирования…
end
wr
… замыкает скрипт, команда сохранения нового маркера…
mk v2017080101
sh flash:
… проверяем результат на предмет наличия маркера актуальной конфигурации, если маркера нет, идем дальше…
delete /recursive /force flash:v2016071001
delete /recursive /force flash:v2016101001
… тут удаляются все старые маркеры…
delete /recursive /force flash:v2016111101
conf t
… далее идет основной код конфигурирования…
end
wr
… замыкает скрипт, команда сохранения нового маркера…
mk v2017080101
Введение “эталонного скрипта” совпало с формированием доступных до авторизации сервисов, поэтому конфигурации могли меняться несколько раз в неделю. Разработанная система могла за пару минут изменить конфигурацию всего доступного оборудования в поездах. В этот момент у пользователей полностью пропадал Wi-Fi на несколько минут, в том числе переставал “светить” SSID Wi-Fi сети.
Всплески также сказывались на инфраструктуре: все подключенные в тот момент пользователи стихийно переподключались к сети после завершения настройки. Это могло привести к падению сервисов, чувствительных к интенсивности нарастания нагрузки.
В результате мы поменяли схему еще раз. Сейчас эталонный скрипт запускается каждый день рано утром с открытием метро и “ловит” оборудование в поездах, которые только выходят на линии и оказываются в сети. Количество доступных попыток настроено так, чтобы к закрытию метро скрипт прекращал работу. Таким образом, поезда проверяются и настраиваются по мере выхода на линию без существенного влияния на пользователей сети. Такое решение позволило отказаться от второстепенного опроса доступности оборудования и снизило ресурсоемкость автоконфигуратора примерно в 5 раз.
Лучше, чем швейцарский нож
Почти за три года использования сервис модернизировали четыре раза, последний — при портировании на сеть петербургского метрополитена. Самый долгий up-time без перезагрузок был более полугода, а перезагрузка была связана с необходимостью обновления самого сервиса. С помощью сервиса мы также настраивали и обновляли прошивки контроллеров, роутеров и радиооборудования, а также конфигурировали внутривагонные коммутаторы, перезаливали прошивки тоннельного оборудования и даже пробовали автоматически перезагружать интерфейсы на оборудовании станционных узлов в случае деградации. Разработанная система оказалась настолько удачной, что до сих пор не возникло существенных потребностей в каком-то новом решении.
А еще у нас есть открытые вакансии
Посмотрите их здесь