Child pages
  • Краткий обзор ConfDB
Skip to end of metadata
Go to start of metadata


Подробная документация доступна по ссылке: ConfDB Overview, мы же кратко остановимся на основных вещах.

Существует множество способов хранения данных. Они появляются для при решении задач, и позволяют сохранять и работать с данными удобнее/быстрее/проще. В НОКе давно существует средство работы с конфигурацией основанное на раскладке оной на факты. Например, есть факты: имя хоста, адреса `NTP` серверов, при проходе по тексту конфигурации они заполняются обнаруженными там значениями. После этого и передаются движку CLIPS, который по результатам проверок выдаст результат (прошли/не прошли). Механизм работал но, с недостатками:

  1. Нельзя определить факты только для какого-то профиля.
  2. Невозможны пользовательские расширения (требовалось править базовый код системы)
  3. Библиотека PyCLIPS перестала развиваться и не работала под 3 питон
  4. Ресурсоёмкость: все факты загружались в память и чем больше устройств необходимо обработать, тем больше памяти надо.

Для преодоления недостатков был реализован новый механимз - ConfDB. В его основу положен список правил (`синтаксис`) после прохождения которых получаем дерево: ConfDB Syntax. В интерфейсе это выглядит так: ...


Новый механиз позволяет:

  • Расширять основной синтаксис новыми фактами без правок основного кода
  • Использовать единый язык запросов
  • Положить данные в БД, ускоряя массовую обработку

Синтаксис


Базовый синтаксис можно посмотреть командой ./noc confdb syntax:

.....

interfaces
  *<interface>
    type
      <type>
    description
      <description>
    admin-status
      <admin_status>
    mtu
      <mtu>
    speed
      <speed>
    duplex
      <duplex>
    flow-control
      <flow_control>

.....


Файлы с описанием расположены в папке noc/core/confdb/syntax. Сам формат описания выглядит пугающе (тут главное понимать DEF - узел дерева, если название узла без кавычек (например IF_NAME),  то вместо него будет подставлено значение и будет новая ветка):


INTERFACES_SYNTAX = DEF(
    "interfaces",
    [
        DEF(
            IF_NAME,
            [
                INTERFACES_META_SYNTAX,
                DEF(
                    "type",
                    [
                        DEF(
                            CHOICES(
                                "physical",
                                "SVI",
                                "aggregated",
                                "loopback",
                                "management",
                                "null",
                                "tunnel",
                                "other",
                                "template",
                                "dry",
                                "unknown",
                            ),
                            required=True,
                            name="type",
                            gen="make_interface_type",
                        )
                    ],
                ),
                DEF(
                    "description",
                    [DEF(ANY, required=True, name="description", gen="make_interface_description")],
                ),
                DEF(
                    "admin-status",
                    [
                        DEF(
                            BOOL,
                            required=True,
                            name="admin_status",
                            gen="make_interface_admin_status",
                        )
                    ],
                ),
                DEF("mtu", [DEF(INTEGER, required=True, name="mtu", gen="make_interface_mtu")]),
                DEF(
                    "speed", [DEF(INTEGER, required=True, name="speed", gen="make_interface_speed")]
                ),
                DEF(
                    "duplex", [DEF(BOOL, required=True, name="duplex", gen="make_interface_duplex")]
                ),


Но позволяет строить дерево и легко расширяется дополнительными полями (путём присоединения к какому-либо узлу). Например, можно для Huawei можно добавить состояние `bpdu` на интерфейсе, примерно так:

SYNTAX = [
        DEF(
            "interfaces",
            [
                DEF(
                    IF_NAME,
                    [
                        DEF(
                            "bpdu",
                            [
                                DEF(
                                    BOOL,
                                    required=False,
                                    name="enabled",
                                    gen="make_interface_ethernet_bpdu",
                                )
                            ],
                        )
                    ],
                    multi=True,
                    name="interface",
                )
            ],
        )
    ]


И в выводе ./noc confdb syntax --profile Huawei.VRP появится:

interfaces
  *<interface>
    bpdu
      <enabled>


Определяя свои расширения базового синтаксиса можно расширять confdb в зависимости от потребностей.


 Запросы

Описание языка запросов доступно в документации: ConfDB Query. Чем-то он напоминает Prolog. Для примера запросим интерфейс c именем GigabitEthernet0/0/1 у которого есть description:

Match('interfaces', X, 'description', Y) and Filter(X=="GigabitEthernet0/0/1") and Del(Y)

сам запрос состоит из Цепочки предикатов, разделённых словами and (в этом случае исполнение идёт друг за другом) и/или or (исполняются вместе).

  • Предикат - конструкция вида <FUNC_NAME>(agrs), где FUNC_NAME - название применяемой функции, `args` - список аргументов. В примере: Match, Filter, Del
  • Путь (confdb path) - содержимое предиката (указывается в скобках). Состоит из списка элементов дерева. Если оный указан в кавычках ('interfaces', 'description') - то ищется точное совпадение а если без (X, Y) обозначает переменную, которой присвоится элемент
  • Контекст - место хранения переменных. После выполнения всех предикатов в запросе становится результатом. Можно посмотреть предикатом Dump.

Разберём выполнение запроса шаг за шагом:

  1. В самом начале запроса *контекст* пуст. И если выполнить, получим пустоту в результате. Поэтому первым предикатом, обычно, идут:
    1. Match и NotMatch. Выполняется запрос к ConfDB. Если в пути есть переменные - они заполняются значениями.
    2. Set - устанавливает переменной указанное значение
 ./noc confdb query --object "200" --query "Match('interfaces', X, 'description', Y)"
 
 Result:
 {'Y': 'description to_11_2.1', 'X': 'GigabitEthernet0/0/1'}
 {'Y': 'description to_AGG1', 'X': 'GigabitEthernet0/0/2'}

В данном случае мы получили список интерфейсов у которых заполнено описание. Их имена в переменной X, а описания в переменной Y

  1. Операции над контекстом:
    1. Filter - проверка контекста над определёнными условием
    2. Re - проверка на соответствие регулярному выражению
    3. HasVLAN - проверка попадания влана в фильтр
    4. Group - схлопывание контекстов
    5. Collapse - разворачивание контекста в несколько
# ./noc confdb query --object "200" --query "Match('interfaces', X, 'description', Y) and Filter(X=='GigabitEthernet0/0/1')"
 
Result:
{'Y': 'description to_11_2.1', 'X': 'GigabitEthernet0/0/1'}

Мы оставили только интерфейс с именем `GigabitEthernet0/0/1`
  1. Вывод контекста
    1. Dump - распечатать контекст
    2. Fact - установить значение в базе
    3. Sprintf - распечатать переменную
# ./noc confdb query --object "200" --query "Match('interfaces', X, 'description', Y) and Dump("Stage2") and Filter(X=='GigabitEthernet0/0/1')"
 Stage2: {'Y': 'description to_11_2.1', 'X': 'GigabitEthernet0/0/1'}
 {'Y': 'description to_11_2.1', 'X': 'GigabitEthernet0/0/1'}

 Result:
 Stage2: {'Y': 'description to_AGG1', 'X': 'GigabitEthernet0/0/2'}

Dump удобно использовать для отладки запросов, впрочем нико не мешает просто выполнять их поэлементно.

Помимо CLI для запросов в графическом Веб интерфейсе в форме ManagedObject по кнопке ConfDB доступна возможность выполнения (кнопка query).

Возможности

  • Валидация - проверка некоего выражения на истинность (не пустой контекст) или ложность (пустой контекст) !описана тут (валидация конфигурации)
  • Фильтрация - получение списка устройств или интерфейсов, соответсвующих условию (запросу)
  • Выборки - извлечение информации из ConfDB (н-р описания всех интерфейсов, или поддержка интерфейсами протоколов - `LLDP`)

Наполнение (как заполнить)

Для наполнения ConfDB собранная конфигурация оборудования проходит несколько этапов:

  • токенизация - разбивает исходную конфигурацию на отдельные слова (токены) для последующей обработки Подробнее тут. Указывается в настройках профиля:
  • нормализация - собирает дерево ConfDB по найденным в токенах значениям. Подробнее смотреть тут: ConfDB Normalizer
  • примененени `апликаторов` позволяют производить манипуляции над построенным деревом и применяются для:
    • Задания умолчаний
    • Заполнения дополнительной информации (секция `meta`)
    • Модификации в зависимости от настроек


  • No labels