# Модуль для работы с Sysrepo в Klish3 ## Обзор Модуль klish-plugin-sysrepo предназначен для работы с хранилищем конфигурации [Sysrepo](#https://www.sysrepo.org/) из программы [Klish версии 3](#https://klish.libcode.org). Klish позволяет организовать интерфейс командной строки, содержащий только команды, заданные пользователем при конфигурировании klish. Хранилище Sysrepo использует язык моделирования данных [YANG](#https://datatracker.ietf.org/doc/html/rfc6020) для формирования схемы хранимой конфигурации, а также хранит саму конфигурацию. Обычно хранимая конфигурация относится к какой-либо встроенной системе, например к маршрутизатору. Принцип хранения и управления конфигурацией, используемый в klish-plugin-sysrepo, похож на подход, применяемый в маршрутизаторах "Juniper". Схема конфигурация описана YANG файлами, а доступ и редактирование элементов конфигурации осуществляется с помощью специальных команд, доступных из klish. Всю информацию об используемой YANG схеме klish-plugin-sysrepo получает из Sysrepo автоматически. Проект содержит файл `xml/sysrepo.xml`, который, будучи добавленным к файлам конфигурации klish, объявляет новый `VIEW` с именем "sysrepo". Этот `VIEW` содержит готовые команды для редактирования конфигурации Sysrepo. Вся работа модуля с Sysrepo осуществляется с помощью библиотечных функций Sysrepo и библиотеки [`libyang`](#https://github.com/CESNET/libyang). Проекты Sysrepo, libyang и klish требуются для сборки и работы модуля klish-plugin-sysrepo. ## Хранилище конфигурации Система Sysrepo поддерживает четыре хранилища конфигурации. * `running` - текущая действующая конфигурация. Состояние системы соответствует этой конфигурации. Но эта не та конфигурация, которую редактирует администратор. * `candidate` - редактируемая конфигурация. "Кандидат" на то, чтобы стать действующей конфигурацией. Однако изменения в `candidate` никак не влияют на реальное состояние системы. Только по факту того, что администратор, специальной командой, записывает содержимое `candidate` в `running` будут происходить изменения в системе. Т.е. изменения применяются не по одному, а "все разом". Таким образом поддерживается целостность и непротиворечивость действующей конфигурации. Все описанные ниже команды работают с `candidate` конфигурацией, если не указано иное. * `startup` - конфигурация, сохраненная на диске. Только эта конфигурация может пережить перезагрузку системы. В случае модуля klish-plugin-sysrepo хранилища `startup` и `running` всегда идут в паре. Т.е. модуль поддерживает их состояние одинаковым. * `operational` - это хранилище не имеет прямого отношение к обсуждаемой теме и упоминаться тут больше не будет. ## Путь KPath Многие команды для работы с конфигурацией используют "путь". Это путь в YANG схеме или вернее в заполненной значениями конфигурации, построенной по YANG схеме. YANG схема является ветвистой и многоуровневой. Схема может содержать "списки", в которых элементы идентифицируются по "ключу". Элементами пути могут быть как узлы YANG схемы, так и ключи, потому что конфигурация ветвится в зависимости от этих ключей. Проекты Sysrepo и libyang используют ["XPath"](#https://www.w3schools.com/xml/xpath_intro.asp) для доступа к элементам конфигурации. Несмотря на то, что XPath имеет развитый синтаксис и возможности, он не подходит для использования в интерфейсе командной строки. XPath довольно сложен и не будет интуитивно понятен оператору. Поэтому для доступа к элементам конфигурации в klish-plugin-sysrepo используется упрощенный вариант пути. Для определенности, назовем его "KPath" (Klish path), чтобы потом ссылаться на его формат и не путать с другими разновидностями путей. Элементы пути в KPath отделяются друг от друга пробелами. Элементами пути являются узлы YANG схемы, значения ключей и элементы `leaf-list` (см. YANG). Если значение ключа или элемент `leaf-list` содержит пробелы, то они заключаются в кавычки. Предположим есть такой фрагмент YANG схемы: ``` module ttt { namespace "urn:ttt"; prefix ttt; container test { list iface { key "name"; leaf name { type string; } leaf comment { type string; } leaf type { type enumeration { enum ethernet; enum ppp; enum dummy; } } } } } ``` Корректный KPath до элемента, определяющего тип "интерфейса" будет таким: `test iface eth0 type`, где "eth0" - ключ списка "iface", соответствующий элементу "name". KPath до поля комментария для интерфейса "eth1" будет таким: `test iface eth1 comment`. В командах, где требуется ввести путь до элемента конфигурации, KPath будет таким, как описано выше. Для команды `set`, которая устанавливает значение элемента конфигурации, существует расширение формата KPath, так называемые "однострочники". Однострочники позволяют задать значения нескольким элементам конфигурации (`leaf`) одной строкой. Команда `set` вместе с аргументами может выглядеть так: ``` # set test iface eth0 type ethernet comment "Comment with space" ``` В одной строке задается значение типа интерфейса и комментарий. Тут, собственно, путь прерывается значениями полей. ## Команды конфигурирования ### Команда `set` Команда `set` позволяет установить значение элемента конфигурации. ``` # set ``` Чтобы выбрать какому именно элементу следует присвоить значение, указывается [путь KPath](#путь-kpath) до этого элемента а затем само значение. Если значение содержит пробелы, то должно заключаться в кавычки. Здесь элементу, имеющему KPath `test iface eth0 type` присваивается значение `ethernet`: ``` # set test iface eth0 type ethernet ``` Команда `set` может присвоить значения сразу нескольким элементам конфигурации. Читайте про "однострочники" в разделе ["Путь KPath"](#путь-kpath). Пример однострочника: ``` # set test iface eth0 type ethernet comment "Comment with space" ``` При указании пути KPath команде `set` не обязательно, чтобы все компоненты пути уже существовали. Команды из приведенных примеров будут работать даже если интерфейс "eth0" еще не был создан в конфигурации. Недостающие компоненты пути будут созданы автоматически. ### Команда `del` Команда `del` удаляет значение элемента, либо целую ветку конфигурации. ``` # del ``` Например можно удалить комментарий для интрерфейса: ``` # del test iface eth0 comment ``` А можно удалить все настройки для интерфейса "eth0": ``` # del test iface eth0 ``` ### Команда `edit` При входе в режим конфигурирования, пользователь находится в "корне" дерева конфигурации, т.е. в корневом узле схемы. И все пути KPath, которые он указывает при работе с конфигурацией, являются полными (абсолютными) путями от корня схемы до искомого элемента. Это не всегда удобно, если настраивается подсистема с высокой степенью вложенности. Поэтому предусмотрена команда `edit`, которая меняет текущее положение пользователя в дереве конфигурации. ``` # edit ``` Перемещение пользователя по дереву конфигурации подобно перемещению по директориям в файловой системе. Текущий путь в дереве конфигурации отображается в строке, предшествующей приглашению пользователя, внутри квадратных скобок после слова "edit". ``` [edit] # edit test iface eth0 [edit test iface eth0] # ``` После смены текущего пути, все указания KPath становятся относительными. Относительно текущего положения в дереве конфигурации. Например указания KPath в командах `set` и `del` будут относительными. ``` [edit] # edit test iface eth0 [edit test iface eth0] # set type ethernet [edit test iface eth0] # set comment "Comment with space" [edit test iface eth0] # del comment ``` Команда `edit` позволяет менять текущий путь только в направлении углубления вложенности. Команды `top`, `up`, `exit` позволяют двигаться по дереву в противоположном направлении. Обратите внимание, что в команде `edit` нельзя указывать список (узел "list") без указания ключа одного из его элементов. ### Команда `top` Команда `top` меняет текущий путь пользователя в дереве конфигурации на корневой элемент. Если пользователь уже находился в корне дерева, то ничего не происходит. ``` [edit test iface eth0] # top [edit] # top [edit] # ``` ### Команда `up` Команда `up` меняет текущий путь пользователя в дереве конфигурации на один уровень вложенности вверх. Т.е. выходит из текущего пути на один уровень. Если пользователь уже находится в корневом элементе дерева, то ничего не происходит. ``` [edit test iface eth0] # up [edit test] # up [edit] # up [edit] # ``` ### Команда `exit` Команда `exit` аналогична команде `up` с тем отличием, что будучи выполнена в корневом элементе дерева, выходит из режима конфигурирования. ``` [edit test iface eth0] # exit [edit test] # exit [edit] # exit > ``` ### Команда `insert` В YANG схеме может быть определен список (узел "list" или "leaf-list") с параметром "ordered-by user". Это означает, что последовательность элементов списка имеет значение и регулируется пользователем. Команда `insert` позволяет перемещать элементы внутри такого списка. ``` # insert [to_list_key] ``` Прежде чем перемещать элемент внутри списка, его надо создать. Несуществующие элементы перемещать нельзя. Первым параметром команды `insert` указывается KPath до того элемента, который нужно переместить. Далее ключевым словом указывается режим перемещения: * `first` - переместить элемент в начало списка. * `last` - переместить элемент в конец списка. * `before` - разместить элемент непосредственно перед элементом, указанным далее. * `after` - разместить элемент непосредственно после элемента, указанного далее. Для режимов `before` и `after` третьим параметром указывается ключ того элемента, относительно которого выбирается позиция. Обратите внимание, что тут указывается не KPath целиком, а только лишь ключ. ``` [edit] # show acl acl1 acl acl2 acl acl3 [edit] # insert acl acl3 before acl1 [edit] # show acl acl3 acl acl1 acl acl2 [edit] # insert acl acl2 first [edit] # show acl acl2 acl acl3 acl acl1 ``` ### Команда `commit` Команда `commit` подтверждает изменение конфигурации и копирует содержимое хранилища конфигурации `candidate` в хранилище `running`. После успешного выполнения команды, конфигурация, которую редактировал пользователь, применится в системе и станет действующей. Если `candidate` конфигурация содержит ошибки, которые могут быть проверены YANG-схемой, то действующая конфигурация изменена не будет, а на экране появится сообщение об ошибке. При записи конфигурации в хранилище `running`, также конфигурация будет записана в хранилище `startup`, чтобы в будущем "пережить" перезагрузку системы. ### Команда `check` Команда `check` проверяет корректность текущей редактируемой конфигурации относительно YANG-схемы. Успешное выполнение этой команды означает, что команда `commit` может быть выполнена без ошибок. ### Команда `reset` Команда `reset` позволяет откатить все изменения при редактировании конфигурации. Редактируемая конфигурация `candidate` вернется к состоянию действующей конфигурации `running`. ### Команда `show` Команда `show` показывает текущее состояние редактируемой конфигурации. ``` # show [kpath] ``` Опциональный параметр принимает путь KPath. В случае если KPath задан, то на экран будет выводиться содержание только указанной секции. По умолчанию команда `show` использует текущий путь пользователя в дереве конфигурации. ``` [edit] # show test iface eth0 comment "Test desc" type ethernet acl acl2 acl acl3 acl acl1 [edit] # show test iface eth0 comment "Test desc" type ethernet ``` ### Команда `diff` Команда `diff` показывает разницу между редактируемой и действующей конфигурациями. ``` [edit] # show test iface eth0 comment "Test desc" type ethernet acl acl2 acl acl3 acl acl1 # # <Тут изменения конфигурации> # [edit] # show test iface eth0 comment "New comment" type ethernet acl acl2 acl acl1 acl acl4 ## diff test iface eth0 = comment "New comment" -acl acl3 +acl acl4 ``` Вновь добавленные строки обозначаются символом `+` в начале строки и зеленым цветом (если включена подсветка). Удаленные строки обозначаются символом `-` в начале строки и красным цветом (если включена подсветка). Измененные строки обозначаются символом `=` в начале строки и желтым цветом (если включена подсветка). ### Команда `do` Команда `do` позволяет выполнять команды командного режима, не выходя из режима конфигурирования. Команда `do` используется как префикс и после нее сразу вводится команда командного режима. ``` [edit] # do show running ``` ## Настройки модуля При подключении модуля к системе klish элементом `PLUGIN`, в теле элемента `PLUGIN` можно задать настройки для модуля. Настройки регулируют некоторые особенности поведения модуля. ### Настройка `ShowBrackets` Поле может принимать значения `y` и `n`. В случае, если задано `y`, то команды, показывающие конфигурацию, отображают фигурные скобки, выделяющие секции и уровни вложенности. ``` test { iface eth0 { comment "Test desc" type ethernet } } ``` По умолчанию отображение фигурных скобок включено. ### Настройка `ShowSemicolons` Поле может принимать значения `y` и `n`. В случае, если задано `y`, то команды, показывающие конфигурацию, отображают символ `;` в конце строк с "листьями" (узлы `leaf`). ``` test iface eth0 { comment "Test desc"; type ethernet; } } ``` По умолчанию отображение символа `;` включено. ### Настройка `KeysWithStatement` Существует два варианта, как указывать ключи элемента списка. Первый вариант - последовательно задавать только значения ключей, не указывая имя поля. В этом случае порядок ввода ключей важен. Такое поведение будет использоваться, если задана настройка `KeysWithStatement = n`. Второй вариант - значения могут задаваться вместе с именем ключа. В таком случае порядок ввода ключей - не важен. Такое поведение будет использоваться, если задана настройка `KeysWithStatement = y`. Предположим, что ключами списка "интерфейсы" являются поля `name` и `type`. Еще предположим что `FirstKeyWithStatement = y`. Команда установки "комментария" для интерфейса будет выглядеть следующим образом, если `KeysWithStatement = y`: ``` # set test iface name eth0 type ethernet comment "Comment" ``` Если `KeysWithStatement = n` то следующим образом: ``` # set test iface eth0 ethernet comment "Comment" ``` По умолчанию используется `KeysWithStatement = y`. ### Настройка `FirstKeyWithStatement` Иногда удобно задавать ключи элемента списка, указывая имя ключа и его значение, но при этом первый ключ, указывать без имени ключа, только значение. Такое поведение будет использоваться, если `FirstKeyWithStatement = n`. Это установка используется по умолчанию. Если `FirstKeyWithStatement = y`, то первый ключ, также, как и все последующие, нужно указывать с именем ключа. > Если `KeysWithStatement = n`, то настройка `FirstKeyWithStatement` > игнорируется. Если `FirstKeyWithStatement = y`: ``` # set test iface name eth0 type ethernet ``` Если `FirstKeyWithStatement = n`: ``` # set test iface eth0 type ethernet ``` ### Настройка `DefaultKeys` По стандарту YANG все ключи списка являются обязательными. Значения по умолчанию (директива `default`) для ключей игнорируются. Однако, если у списка много ключей, то может быть удобно некоторые из них опускать при вводе. Чтобы использовать такое поведение, нужно указать настройку `DefaultKeys = y`. Эта настройка действует совместно с YANG-расширением `klish:default`, определенным в файле `klish.yang`. Если в YANG файле с помощью расширения `klish:default` указано значение по умолчанию для ключа, то в случае, если администратор не ввел значение этого ключа явно, то ключу сопоставляется значение по умолчанию. Обратите внимание, что расширение не нарушает стандарт YANG, относительно того, что обязательно должны быть введены все ключи. Так как значения по умолчанию используются только на этапе формирования запроса, внутри плугина. YANG запрос содержит все ключи. > Если используется настройка `FirstKeyWithStatement = n`, и при этом первый > ключ имеет значение по умолчанию, то настройка перестает работать и ключ > должен быть введен с указанием имени ключа, как и все последующие ключи. > Настройка `DefaultKeys` игнорируется в случае, если `KeysWithStatements = n`. Пример YANG файла с использованием ключей по умолчанию: ``` ... import klish { prefix "klish"; } ... list list { key "key1 key2 key3"; leaf key1 { description "First key"; type string; klish:default "def1"; } leaf key2 { description "Second key"; type string; klish:default "def2"; } leaf key3 { description "Third key"; type string; } leaf el1 { description "First el"; type string; default "el1-def"; } leaf el2 { description "Second el"; type string; } } ``` Администратор может ввести следующую команду, опустив ключи `key1` и `key2`, т.к. они имеют значения по умолчанию: ``` # set list key3 nnn el1 mmm # show ... list key1 def1 key2 def2 key3 nnn { el1 mmm } ... ``` ### Настройка `ShowDefaultKeys` Если значение настройки установлено в `n`, а значение ключа списка (в режиме `DefaultKeys = y`) совпадает со значением по умолчанию, то такой ключ не будет показываться на экране при выводе конфигурации. ### Настройка `HidePasswords` Если в конфигурации хранятся пароли или хэши паролей, то такую информацию желательно не показывать на экране. Чтобы скрыть значения полей при выводе на экран, используется настройка `HidePasswords = y`. Эта настройка действует совместно с YANG-расширением `klish:password`, определенным в файле `klish.yang`. YANG-модуль, в котором одно из полей помечено как "пароль". ``` ... import klish { prefix "klish"; } ... leaf pass { type string; klish:password; } ... ``` Затем, если администратор захочет посмотреть содержимое конфигурации, то увидит следующее: ``` # show ... pass ... ``` Значение поля заменяется на строку ``. ### Настройка `Colorize` Поле может принимать значения `y` и `n`. В случае, если задано `y`, то при отображении конфигурации или изменений в конфигурации, характерные элементы будут выделяться цветом. > Сейчас цветовое выделение реализовано только в команде `diff`. Новые элементы > выделяются зеленым, удаленные - красным, а те, что изменили свое значение - > желтым. Некоторые терминалы, в основном устаревшие, могут не поддерживать цвета. Поэтому в каких то случаях может быть полезно отключить настройку `Colorize`. ### Настройка `Indent` Поле принимает числовое значение. Задает величину отступа для каждого уровня вложенности. Измеряется в количестве символов "пробел" в начале строки. По умолчанию имеет значение `2`. ### Настройка `EnableNACM` По умолчанию модуль NACM (ietf-netconf-acm) считается служебным и его настройка невозможна. Элементы скрыты от пользователя. Настройка `EnableNACM = y` заставляет рассматривать модуль NACM в качестве обычного модуля. Пользователь получает возможность управлять NACM. ### Настройка `Oneliners` Если настройка `Oneliners = y` (используется по умолчанию), и у элемента менее двух потомков, то этот элемент и его единственные потомок будут показаны в одну строку. Открывающие и закрывающие скобки показываться не будут. Элементы, вообще не имеющие потомков, будут показаны также без открывающих и закрывающих скобок. ### Пример настройки модуля ``` ShowBrackets = y ShowSemicolons = y KeysWithStatement = y FirstKeyWithStatement = n Colorize = y Indent = 2 HidePasswords = y DefaultKeys = y EnableNACM = n ```