CLI - Command Line Interface

CLI - сиэлай, кли, сли, слай, слаи, консоль, терминал, командная строка. Этому механизму уже лет 60. И он никуда не делся. Он живее всех живых - где-то для отладки, где-то для эксплуатации, зачастую для конфигурации и даже для ежедневной работы.
На компьютерах, серверах, виртуальных машинах, коммутаторах, маршрутизаторах, фаерволах, АТС, базовых станциях. Трудно найти такое оборудование, где нет CLI, пусть даже хорошо спрятанного.
И в этом его сила - 100% функциональности на 100% сетевых устройств можно настроить через CLI. Ладно 99,9% - придётся выкинуть некоторое альтернативное оборудование.
Это породило миллионы строк кода на Perl, PHP, Python, Go, Ruby, развесистые джинджа-шаблоны и по 300 экспектов в каждом скрипте.
И дало работу тысячам кодеров, выросших из сетевиков и админов.
Вот уже лет 30, а то и больше мы старательно пишем скрипты, которые с той или иной степенью успеха прикидываются человеком перед сетевой коробкой.

И ещё долго мы не останемся без дела - выпускают всё новые версии софта, ещё более другие модели железа, постоянно меняется CLI, и там, где вчера был string, завтра будет integer. И там, где вчера было no some shitty service enable, завтра будет some shitty service disable. И там, где вчера на вопрос интерфейса надо было ответить yes, завтра вылезет ошибка.

Клянусь, это увлекательное путешествие продлится ещё десятилетия.
А чем же оно увлекательно?
  1. Модели конфигурации не формализованы
  2. Модель и поведение не зафиксированы
  3. CLI интерактивен
  4. Формат данных не структурированный
  5. Нет явного признака успешности операции
  6. Сложно вычислять разницу между целевой и текущей конфигурацией
  7. Сложно считать конфигурационный патч
  8. Транзакционность не всегда доступна
  9. Поддержание целевого состояния – задача инженера
Выше 9 смертных грехов CLI, которые обусловили рождение моделей данных конфигурации, языков их описания, протоколов, как SNMP, NETCONF и gNMI.
Если всё по каждому из них понятно, просто пропускайте следующую секцию.

9 грехов CLI

1. Модели конфигурации не формализованы

Есть такое? Есть такое.
Как мы узнаём, какие команды с какими аргументами в каком порядке надо дать?
Правильно - идём в Command reference guide на сайте производителя и дальше методом проб и ошибок разбираемся в терминале. Или в обратном порядке. Но эти два способа (и ещё помощь друга) - это то, как мы узнаём модель данных конфигурации.
И скажем так: она наверняка есть - ведь каждый раз одна и та же команда приводит к одному и тому же результату (правда ведь? Правда?)
Знаем как настраивать интерфейсы, знаем как они должны называться, где будет IPv4, а где IPv6 адреса? Если мы введём что-то неправильно, CLI ругнётся, но мы не отправим OS в kernel panic или ASIC в рестарт?
Просто эта модель не формализована. Или по крайней мере нам об этом не говорят.
И да, своим естественным интеллектом мы рано или поздно такую модель в своей голове выстраиваем и научаемся ею пользоваться.
Но для того, чтобы написать код, нам придётся её хорошо или плохо самим формализовать - иерархия, порядок ввода команд, последовательность аргументов, типы значений. И скорее плохо, конечно.

2. Модель и поведение не зафиксированы

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

3. CLI интерактивен

expect("Вы точно хотите выключить bgp-сессию, mpls на всей коробке [Y/n]?"] Yes!
expect("Вы точно хотите выключить электричество в серверной [Y/n]?"] No!

4. Формат данных не структурированный

Мы засылаем туда неструктурированный текст.
Мы получаем оттуда неструктурированный текст.
Мы его крафтим, мы его парсим. Мы пишем jinja-шаблоны и regexp’ы. Мы прожигаем свою жизнь.
Лучше json’ы перекладывать.
Строго говоря, будь-то json или вывод show version, в итоге это всё равно поток байтов и по сути текст. Только в одном случае в нём есть структура, а в другом - это просто набор символов.

5. Нет явного признака успешности операции

Вывод CLI не означает ни успех, ни провал.
Warning ещё не означает, что что-то пошло не так.
Отсутствие вывода - ещё не признак успешности.

6. Сложно вычислять разницу между целевой и текущей конфигурацией

Казалось бы нужно просто подифать два текста.
Вот только в этих текстах имеет значение, порядок строк.
Одна и та же конфигурация может быть (и будет) разной для разных версий ПО.
Различающийся же регистр, напротив, может ничего не значить в одном месте, а в другом значить.
Одна и та же команда, в разных контекстах может означать разное (выключите MPLS на интерфейсе или в глобальном режиме - посмотрите на последствия).
Даже IPv6-адреса могут быть записаны в сокращённом или полном виде.

7. Сложно считать конфигурационный патч

Как следствие предыдущего пункта - выяснить, какие команды нужно применить - тоже нетривиально.
Но не только это.
Дело в том, что нужно уметь не только правильно добавлять, но и правильно удалять - а способов - не один и не два. Обратная команда не всегда формируется как отрицание прямой. Часто нужны не все её параметры.
В каком порядке отменять - и не поломает ли это чего-то ещё?
Даже не всегда команды после применения выглядят так же, как их применяли.

8. Транзакционность не всегда доступна

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

9. Поддержание целевого состояния – задача инженера

Ооо, это самое интересное - а как собственно привести конфигурацию к тому состоянию, которое мы желаем увидеть, а не просто применить новую конфигу?
Кто и как должен посчитать конфигурационный патч, применить только его и проверить за собой, что рантайм соответствует эталону?
Но тут стоит быть чуть более честным - не всегда CLI настолько плох. Некоторые вендоры генерируют CLI-интерфейс из YANG-модели, что гарантирует чёткое соответствие между тем, что и как конфигурируется через CLI или любые другие интерфейсы.
Например, в Nokia SR Linux интерфейс командной строки, а так же gNMI, JSON-RPC и внутренние приложения работают с единым API - mgmt_srv - поэтому не только формализованы из одной и той же YANG-модели, но и имеют одинаковые возможности по чтению/записи конфигурации.
Дифы, коммиты, датасторы и прочее, тоже могут быть сделаны с умом - как у той же Nokia или у Juniper.
Но это всё, конечно, не отменяет факта работы с неструктурированным текстом.

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

Далее был опыт с SNMP и всеми связанными протоколами (приглашаю пройти в пятую часть книги).
Признаем его удачным лишь по той простой причине, что он позволил сформулировать требования к новым интерфейсам и протоколам.
Не исчерпывающий список можно сформулировать так:
  • Представление данных в структурированном виде,
  • Разделение конфигурационных и операционных данных,
  • Читаемость для человека исходных данных и самой конфигурации,
  • Воспроизводимость - задачу на исходных данных можно запустить повторно - проиграть,
  • Механизм основан на формальных моделях,
  • Транзакционность изменений и их откат,
  • Поддержание целевого состояния.

Не все они появились сразу. Не все они появились. Но это понятная и приятная цель.

И на замену SNMP, в подмогу CLI зародился NETCONF, эксплуатирующий идею RPC - Remote Procedure Call.
Что за RPC, какое у него отношение с API вы так же можете узнать из пятой части.
Ну, только если коротко.