Пример заполнения шаблона

Рассмотрим структуру шаблона на примере: создадим шаблон модели здоровья ПАК МБД.П.

Пусть шаблон отображает следующие сведения о ПАК:

  • общий статус ПАК;

  • состояние кластера PostgreSQL;

  • состояние узлов модуля баз данных и степень утилизации их ресурсов.

По этим сведениям подсистема мониторинга построит дерево из панелей трёх видов: карточка ПАК, карточки модулей баз данных и списки их узлов.

Назначение полей, которые встречаются ниже, описано в разделе Спецификация шаблонов модели здоровья.

Шаг 1. Заголовок шаблона

Шаблон — это файл формата YAML, поэтому сначала создадим файл с расширением .yml.

Начнём с полей, которые описывают шаблон целиком: код типа ПАК (uid — для МБД.П это mbd_p), название шаблона в веб-интерфейсе (title), номер версии шаблона (version), номер версии схемы (schema_version — для новых шаблонов 1.1) и период обновления статусов панелей в секундах (refresh_interval). Добавим эти поля в файл:

---
uid: mbd_p
title: МБД.П
version: v1.0
schema_version: "1.1"
refresh_interval: 30

Комбинация значений uid и version должна быть уникальной среди загруженных шаблонов.

Шаг 2. Панель общего статуса

Первая панель — карточка ПАК. Она служит корнем дерева: остальные панели вложены в неё напрямую или через другие панели.

Общий статус ПАК будем вычислять по активным оповещениям. Это делает запрос в поле status_query: он собирает оповещения ПАК из ALERTS, и если среди них есть оповещение уровня critical, статус панели — red, если warning — yellow, а без оповещений — green.

Состав панели определяет запрос в поле list_query: сколько рядов он вернёт, столько объектов появится на панели. Здесь запрос возвращает единственный ряд — сам ПАК из объектной модели, поэтому карточка будет одна.

Вместо конкретных идентификаторов в запросах используются встроенные переменные: при построении модели подсистема мониторинга заменит ${pak_id} идентификатором текущего ПАК, а ${entity_id} — идентификатором текущего объекта. Благодаря переменным один и тот же шаблон работает на любом экземпляре МБД.П.

На карточке выведем тип и описание ПАК. Блок meta сохраняет одноимённые метки из ответа list_query, а подзаголовок карточки обращается к сохранённому значению через ${meta.type}. Тем же способом можно сохранить и любую другую метку из ответа.

Панель отображается карточкой, поэтому тип панели — grid, тип объекта — pak, а внешний вид задаёт блок card_template. Его поле indicator определяет, что красит карточку: индикаторы (true) или оповещения из status_query (false).

Собираем панель — допишем в конец файла блок panels с первой записью:

panels:
  - id: ${pak_id}
    title: ПАК ${pak_id}
    type: grid
    panel_type: pak
    list_query: 'vision_object_pak_info{_pak_id="${pak_id}"}'
    meta:
      - name: type
        source: type
      - name: description
        source: description
    status_query: 'max by (_pak_id, alertname, severity, _cids) (ALERTS{_pak_id="${entity_id}", alertstate="firing"})'
    card_template:
      title: "ПАК ${id}"
      subtitle: "Тип: ${meta.type}"
      indicator: true

При изменении status_query не удаляйте метку объекта панели (здесь — _pak_id) из списка группировки max by (…​), иначе подсистема мониторинга не сможет привязать оповещения к панели, и её статус станет gray.

Шаг 3. Панель модуля баз данных

Состояние кластера PostgreSQL покажем на карточке модуля баз данных.

Поскольку модулей баз данных в ПАК может быть несколько, используем для описания панели конструкцию repeat_for: её запрос возвращает все модули типа «Модуль баз данных», и панель повторяется для каждого из них. Значение метки, названной в id_field, при этом становится переменной ${_module_id} — она делает уникальными идентификатор и заголовок каждой карточки.

Состояние кластера оценим двумя индикаторами из блока indicators:

  • количество узлов кластера Pacemaker в статусе online: меньше трёх — жёлтый, меньше двух — красный;

  • доля использованных соединений PostgreSQL:

    • ≥ 80% — жёлтый;

    • ≥ 90% — красный.

Каждый индикатор состоит из идентификатора (id), подписи (title), PromQL-запроса показателя (query) и порогов (thresholds). По этому же образцу можно добавить собственные индикаторы или скорректировать пороги.

Заключайте правило порога в кавычки, иначе YAML воспримет значение, начинающееся с >, как начало многострочного блока.

Цвет карточки должны определять именно индикаторы, поэтому в блоке card_template параметру indicator присвоим значение true. Если индикаторы в порядке, наличие оповещений не будет влиять на цвет карточки. При этом числовые значения будут отображаться.

Счётчик из блока entities выведет на карточку количество узлов модуля: его поле query ссылается на идентификатор панели узлов db-nodes-${_module_id}, которую опишем на следующем шаге.

Остальное повторяет карточку ПАК: блок meta сохраняет тип и описание модуля, а status_query собирает оповещения — теперь по метке _module_id.

Собираем панель — допишем её в блок panels после карточки ПАК:

  - id: module-db-${_module_id}
    title: "Модуль ${_module_id}"
    type: grid
    panel_type: module
    repeat_for:
      source: ${pak_id}
      id_field: _module_id
      list_query: 'vision_object_module_info{_pak_id="${pak_id}", type="Модуль баз данных"}'
    list_query: 'vision_object_module_info{_pak_id="${pak_id}", _module_id="${_module_id}", type="Модуль баз данных"}'
    meta:
      - name: type
        source: type
      - name: description
        source: description
    status_query: 'max by (_module_id, alertname, severity, _cids) (ALERTS{_module_id="${entity_id}", alertstate="firing"})'
    entities:
      - id: nodes
        title: Ноды
        query: db-nodes-${_module_id}
    indicators:
      - id: cluster_nodes_online
        title: "Ноды кластера online (шт.)"
        query: 'count(ha_cluster_pacemaker_nodes{_module_id="${_module_id}",status="online"} and on(node) ha_cluster_corosync_member_votes{_module_id="${_module_id}",local="true"})'
        thresholds:
          warning: "< 3"
          critical: "< 2"
      - id: used_connections
        title: "Использовано соединений (%)"
        query: 'max(label_replace(spectrum_pg_used_connections{service_name!="",node_name!=""},"_node_id","$1","node_name","(.*)") and on(_node_id) vision_object_node_info{_pak_id="${pak_id}",_module_id="${_module_id}"})'
        thresholds:
          warning: ">= 80"
          critical: ">= 90"
    card_template:
      title: "Модуль ${id}"
      subtitle: "Тип: ${meta.type}"
      indicator: true

Шаг 4. Панель узлов

Узлы модуля баз данных выведем списком: одна строка — один узел. Список, как и карточка модуля, повторяется для каждого модуля баз данных — правило repeat_for то же, только его поле source ссылается на панель модуля.

Состав списка определяет запрос list_query: он возвращает по одному ряду на каждый узел модуля. Из ответа блок meta сохраняет тип узла и его адреса — обычный и BMC; адрес BMC выводится в подзаголовке строки через ${meta.bmc_address}.

Добавим показатели утилизации ресурсов:

  • CPU:

    • ≥ 80% — жёлтый;

    • ≥ 90% — красный;

  • RAM:

    • ≥ 90% — жёлтый;

    • ≥ 95% — красный.

В запросах этих индикаторов переменная ${entity_id} подставляет идентификатор текущего узла.

По умолчанию, если данные для панели не поступают, она окрашивается в серый цвет. Однако отсутствие метрик с узла — само по себе серьёзная проблема, поэтому в поле indicator шаблона строки (row_template) — значение true: цвет строки определяют индикаторы, а отсутствие их данных поднимает статус узла до red.

Собираем панель — допишем её в блок panels после карточки модуля:

  - id: db-nodes-${_module_id}
    title: "Узел БД ${id}"
    type: list
    panel_type: node
    repeat_for:
      source: module-db-${_module_id}
      id_field: _module_id
      list_query: 'vision_object_module_info{_pak_id="${pak_id}", type="Модуль баз данных"}'
    list_query: 'vision_object_node_info{_pak_id="${pak_id}", _module_id="${_module_id}"}'
    meta:
      - name: type
        source: type
      - name: address
        source: address
      - name: bmc_address
        source: bmc_address
    status_query: 'max by (_node_id, alertname, severity, _cids) (ALERTS{_node_id="${entity_id}", alertstate="firing"})'
    indicators:
      - id: cpu_usage
        title: "Исп. ЦПУ (%)"
        query: '(1 - avg(rate(node_cpu_seconds_total{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}",mode="idle"}[5m])) by (_node_id)) * 100'
        thresholds:
          warning: ">= 80"
          critical: ">= 90"
      - id: ram_usage
        title: "Занято RAM (%)"
        query: '100 - node_memory_MemAvailable_bytes{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}"} / node_memory_MemTotal_bytes{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}"} * 100'
        thresholds:
          warning: ">= 90"
          critical: ">= 95"
    row_template:
      title: "Узел БД ${id}"
      subtitle: "BMC: ${meta.bmc_address}"
      indicator: true

Шаг 5. Связи между панелями

Панели описаны — построим из них дерево. Вложенность панелей задаёт блок relationships: в каждой записи from — идентификатор родительской панели, to — дочерней. Свяжем карточку ПАК с карточками модулей, а модули — со списками узлов:

relationships:
  - from: ${pak_id}
    to: module-db-${_module_id}

  - from: module-db-${_module_id}
    to: db-nodes-${_module_id}

Шаг 6. Правила агрегации

Чтобы проблемы поднимались вверх по дереву, зададим правила агрегации: статус ПАК зависит от карточек модулей, а статус модуля — от его списка узлов.

В каждом правиле target — панель, для которой действует правило, depends_on — список панелей, от которых она зависит. Условие condition: ANY означает, что панель из target меняет цвет при проблеме хотя бы в одной панели из depends_on; при ALL — только когда проблема во всех панелях одновременно. Значение поля type всегда dependency — других типов правил нет.

Допишем блок в конец файла:

aggregations:
  - target: ${pak_id}
    type: dependency
    condition: ANY
    depends_on:
      - module-db-${_module_id}

  - target: module-db-${_module_id}
    type: dependency
    condition: ANY
    depends_on:
      - db-nodes-${_module_id}

Итоговый шаблон

Собранный из всех шагов шаблон готов к загрузке.

Пример заполнения шаблона модели здоровья ПАК МБД.П
---
uid: mbd_p
title: МБД.П
version: v1.0
schema_version: "1.1"
refresh_interval: 30

panels:
  - id: ${pak_id}
    title: ПАК ${pak_id}
    type: grid
    panel_type: pak
    list_query: 'vision_object_pak_info{_pak_id="${pak_id}"}'
    meta:
      - name: type
        source: type
      - name: description
        source: description
    status_query: 'max by (_pak_id, alertname, severity, _cids) (ALERTS{_pak_id="${entity_id}", alertstate="firing"})'
    card_template:
      title: "ПАК ${id}"
      subtitle: "Тип: ${meta.type}"
      indicator: true

  - id: module-db-${_module_id}
    title: "Модуль ${_module_id}"
    type: grid
    panel_type: module
    repeat_for:
      source: ${pak_id}
      id_field: _module_id
      list_query: 'vision_object_module_info{_pak_id="${pak_id}", type="Модуль баз данных"}'
    list_query: 'vision_object_module_info{_pak_id="${pak_id}", _module_id="${_module_id}", type="Модуль баз данных"}'
    meta:
      - name: type
        source: type
      - name: description
        source: description
    status_query: 'max by (_module_id, alertname, severity, _cids) (ALERTS{_module_id="${entity_id}", alertstate="firing"})'
    entities:
      - id: nodes
        title: Ноды
        query: db-nodes-${_module_id}
    indicators:
      - id: cluster_nodes_online
        title: "Ноды кластера online (шт.)"
        query: 'count(ha_cluster_pacemaker_nodes{_module_id="${_module_id}",status="online"} and on(node) ha_cluster_corosync_member_votes{_module_id="${_module_id}",local="true"})'
        thresholds:
          warning: "< 3"
          critical: "< 2"
      - id: used_connections
        title: "Использовано соединений (%)"
        query: 'max(label_replace(spectrum_pg_used_connections{service_name!="",node_name!=""},"_node_id","$1","node_name","(.*)") and on(_node_id) vision_object_node_info{_pak_id="${pak_id}",_module_id="${_module_id}"})'
        thresholds:
          warning: ">= 80"
          critical: ">= 90"
    card_template:
      title: "Модуль ${id}"
      subtitle: "Тип: ${meta.type}"
      indicator: true

  - id: db-nodes-${_module_id}
    title: "Узел БД ${id}"
    type: list
    panel_type: node
    repeat_for:
      source: module-db-${_module_id}
      id_field: _module_id
      list_query: 'vision_object_module_info{_pak_id="${pak_id}", type="Модуль баз данных"}'
    list_query: 'vision_object_node_info{_pak_id="${pak_id}", _module_id="${_module_id}"}'
    meta:
      - name: type
        source: type
      - name: address
        source: address
      - name: bmc_address
        source: bmc_address
    status_query: 'max by (_node_id, alertname, severity, _cids) (ALERTS{_node_id="${entity_id}", alertstate="firing"})'
    indicators:
      - id: cpu_usage
        title: "Исп. ЦПУ (%)"
        query: '(1 - avg(rate(node_cpu_seconds_total{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}",mode="idle"}[5m])) by (_node_id)) * 100'
        thresholds:
          warning: ">= 80"
          critical: ">= 90"
      - id: ram_usage
        title: "Занято RAM (%)"
        query: '100 - node_memory_MemAvailable_bytes{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}"} / node_memory_MemTotal_bytes{_target_type="NODE",_pak_id="${pak_id}",_node_id=~"${entity_id}"} * 100'
        thresholds:
          warning: ">= 90"
          critical: ">= 95"
    row_template:
      title: "Узел БД ${id}"
      subtitle: "BMC: ${meta.bmc_address}"
      indicator: true

relationships:
  - from: ${pak_id}
    to: module-db-${_module_id}

  - from: module-db-${_module_id}
    to: db-nodes-${_module_id}

aggregations:
  - target: ${pak_id}
    type: dependency
    condition: ANY
    depends_on:
      - module-db-${_module_id}

  - target: module-db-${_module_id}
    type: dependency
    condition: ANY
    depends_on:
      - db-nodes-${_module_id}

Загрузите файл и сделайте его активным, как описано в разделе Добавление шаблона.

Готовые шаблоны из поставки можно скачать и посмотреть в них описания остальных панелей: базового модуля, модуля резервного копирования, виртуальных машин и коммутаторов.