Привет, Хабр! В преддверии старта курса "Архитектор сетей" предлагаем прочитать перевод полезной статьи.


Оптимизация модели данных и удаление повторений — это, конечно, здорово, но каким образом мы можем убедиться, что работаем с валидной моделью данных?

На этот вопрос легко ответить в рамках традиционной реализации IPAM/CMDB с использованием внутренней базы данных и пользовательской логики обработки данных, предлагающей REST API, графический интерфейс или и то, и другое. Пользовательская логика обработки данных проверяет данные перед их вводом в базу данных, и, таким образом мы получаем гарантию того, что база данных содержит синтаксически и семантически допустимые данные.

В более простом решении, использующем текстовые файлы для хранения сетевой модели данных (также известной как источник истины или  source-of-truth), сложно выполнить тщательную проверку каждой транзакции, тем более, если для изменения этих файлов вы используете текстовый редактор. В этих случаях вам нужно писать собственный конвейер валидации, используя инструменты, которые проверяют:

  • синтаксис текстового файла;

  • соответствие схеме модели данных;

  • ссылочную целостность.

Используя нашу последнюю модель данных с per-link префиксами, которые хранятся как куча Ansible host_vars файлов и network.yml файл, конвейер валидации должен проверить что:

  • Все файлы соответствуют синтаксису YAML (чтобы сделать это, вы можете использовать такие инструменты как yamllint);

  • Факты о хостах содержат значения hostname и bgp_as для каждого хоста;

  • Сетевая модель данных содержит значение links, которое представляет из себя массив core и edge ссылок;

  • Core ссылки содержат prefix и как минимум два других значения;

  • Edge ссылки содержат одно значение, которое является словарем (или объектом, если вы предпочитаете терминологию JSON) с одним значением.

Для выполнения этих тестов вы можете написать небольшую программу на любом языке программирования или же использовать языки моделирования данных (также называемые схемами), такие как YANG, JSON Schema или XML Schema, которые наложат большинство необходимых проверочных ограничений. Поскольку файлы YAML легко преобразовать в JSON, мы будем использовать jsonschema.

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

Валидация данных хоста

Первым этапом в нашей логике валидации модели данных будет проверка фактов хоста Ansible. Эти факты часто расползаются по нескольким файлам и каталогам или генерируются «на лету» с помощью внешнего скрипта или плагина Ansible. Таким образом, лучший способ получить их — передать задачу программе ansible-inventory, которая создает JSON структуру данных в соответствии с требованиями внешнего инвентарного скрипта (external inventory script).

$ ansible-inventory -i ../hosts --list
{
    "_meta": {
        "hostvars": {
            "S1": {
                "bgp_as": 65001,
                "description": "Unexpected",
                "hostname": "S1"
            },
            "S2": {
                "bgp_as": 65002,
                "hostname": "S2"
            }
        }
    },
    "all": {
        "children": [
            "ungrouped"
        ]
    },
...

Из полученной JSON структуры данных нам нужно извлечь только переменные хоста, и jq идеально подходит для этой работы:

$ ansible-inventory -i ../hosts --list|jq ._meta.hostvars
{
  "S1": {
    "bgp_as": 65001,
    "description": "Unexpected",
    "hostname": "S1"
  },
  "S2": {
    "bgp_as": 65002,
    "hostname": "S2"
  }
}

Если мы хотим использовать утилиту командной строки jsonschema, нам необходимо сохранить результаты в текстовом файле, а затем вызвать утилиту jsonschema с именем текстового файла и файла JSON Schema, в соответствии с которым следует проверить данные.

$ jsonschema -i /tmp/hosts.json hosts.schema.json
{'bgp_as': 65001, 'description': 'Unexpected', 'hostname': 'S1'}: 
Additional properties are not allowed ('description' was unexpected)

Валидация сетевой модели данных

Для проверки network.yml файла мы будем использовать аналогичный подход:

  • Convert YAML file into JSON format with yq

  • Преобразуем YAML файл в формат JSON с помощью yq

  • Run jsonschema on the resulting JSON file

  • Запустим jsonschema на полученном JSON файле

yq <network.yml . >/tmp/$$.network.json
jsonschema -i /tmp/$$.network.json network.schema.json

Как упоминалось выше, JSON Schema позволяет нам проверять грамматику модели данных, а ссылочную целостность — нет. Например:

  • Мы не можем проверить, валидны ли имена хостов, указанные для core или edge ссылок.

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

Пару слов о JSON Schema

Языки моделирования данных не для слабонервных, и JSON Schema не исключение. Замысловатая подача спецификации тоже не особо облегчает жизнь (мне было интереснее читать стандарты ISO или IEEE). К счастью, онлайн-книга Разбираемся с JSON Schema довольно хорошо объясняет все тонкости.

Просто чтобы вы прочувствовали, что такое JSON Schema: вот документ JSON, описывающий ожидаемую структуру данных переменных хоста, полученный из инвентаря Ansible:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://www.ipSpace.net/hosts.schema.json",
  "title": "Ansible inventory data",
  "definitions": {
    ...
  },
  "type": "object",
  "patternProperties": {
    ".*" : { "$ref" : "#/definitions/router" }
  },
  "minProperties": 1
}

Вот что можно сказать об этой схеме:

  • Она описывает инвентарные данные Ansible (Ansible inventory data);

  • Она содержит определения дополнительных схем (см. ниже).

  • Элемент верхнего уровня — это объект (словарь) с некоторыми свойствами (мы знаем, что это инвентарные имена хостов), и каждое свойство должно соответствовать схеме router

  • Минимальное количество свойств — одно (хотя бы один хост в файле инвентаризации).

Определение схемы router находится в свойстве definitions:

"router" : {
  "type" : "object",
  "properties": {
    "bgp_as": {
      "type": "number",
      "minimum": 1,
      "maximum": 65535
    },
    "hostname": {
      "type": "string"
    }
  },
  "required": [ "bgp_as","hostname" ],
  "additionalProperties": false
}

Согласно этой схеме роутер (если быть точнее, факты хоста Ansible, описывающие роутер) — это объект со следующими свойствами:

  • Числовым свойством bgpas, которое должно быть от 1 до 65535;

  • Строковым свойством hostname 

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

Закатываем рукава

JSON схемы хоста и сети, а также исходный код скрипта проверки доступны на GitHub. Не стесняйтесь клонировать репозиторий, менять host_vars файлы или сетевую модель данных и запускать скрипт проверки в своих целях.

Вам также может захотеться исследовать JSON Schema побольше, в частности:

  • выяснить, что делает JSON схема network;

  • добавить необязательное свойство description в модель данных роутера;

  • скорректировать валидацию свойства bgp_as, чтобы разрешить 4-байтовые AS номера в точечной нотации.

Вам понадобятся следующие инструменты:

Больше о валидации данных

Мы рассматриваем валидацию данных и конвейеры CI/CD более подробно в части Validation, Error Handling and Unit Tests нашего онлайн-курса Building Network Automation Solutions.

Дополнительная информация

  • Чтобы узнать больше об использовании моделей данных в решениях для автоматизации сети, ознакомьтесь с модулем 3 нашего онлайн-курса Building Network Automation Solutions.

Далее в программе

  • Data Model Hierarchy

  • Иерархия моделей данных


Подробнее о курсе "Архитектор сетей". Посмотреть запись открытого урока на тему "Overlay. Что это такое и зачем необходимо" можно здесь.