# GUFO Data Model
## Preface
Все инвентарные данные в GUFO, имеющие бизнес-ценность являются сервисами и встроены в общую сервисную модель.
## База данных
Структура БД рассчитана на PostgreSQL с расширениями Citus.
Для удобства управления правами доступа и резервного копирования база данных состоит из схем:
* `main` - основная инвентарная схема
* `fm` - fault management: events/alarms
* `pm` - performance management: метрики и телеметрия
* `mon` - самомониторинг
* `bi` - схема с аналитическими view
## Модели Pydantic
Модели [pydantic](https://pydantic-docs.helpmanual.io)
определяют структуру данных при взаимодействии с внешними процессами:
* Формат REST запросов (FastAPI)
* Структура JSON-полей в БД
* Форматы выгрузок ETL
Модели хранятся в каталоге `models` и разбиты по категориям:
* `models/api/` - модели API
* `models/traits/` - модели БД
* `models/etl/` - модели ETL
* `models/config/` - конфигурация системы
Модели могут быть адресованы в виде строки `<модуль>.<класс>`.
Например, в контексте БД модель `address.Address` модель расположена в модуле `models/db/address` в классе `Address`.
Для загрузки моделей используется Loader API (По аналогии с NOC).
Модели могут быть кастомизированы и находиться в `custom`.
## ServiceTraits
Сервисы разных типов могут иметь разный набор атрибутов. Аттрибуты редко сущесвуют сами по себе. Обычно, они объединяются в группы и описывают один из аспектов взаимодействия с внешним миром. В ООП используется понятиие `Trait`. Trait определяет набор методов, имеющих
определенную семантику использования и может использоваться для параметризации других Trait.
Таблица БД: `main.service_trait`
| Поле | Тип | Constraints | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL UNIQUE | Название Trait |
| description | TEXT | NULL | Описание |
| title | VARCHAR | NULL | Заголовок |
| model | VARCHAR | NOT NULL | Модель Pydantic |
### Trait name
Именнованные сервисы
```python
class NameTrait(BaseModel):
name: str
description: Optional[str]
```
## ServiceType
Тип сервиса определяет поведение системы при работе с сервисом и его модель данных.
Введение нового типа сервисов, обычно, требует соответсвующих моделей, которые могут быть расположены как в базовой системе, так и в custom. В любом случае - доработка системы в той или иной мере.
Предполагается, что ServiceType будет заполняться из коллекций через механизм ETL.
Таблица БД: `main.service_type`
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| description | TEXT | NULL | Описание |
| policy_traits | Array[TraitItem] | NULL | Trait'ы, задаваемые на уровне политики |
| service_traits | Array[TraitItem] | NULL | Trait'ы, задаваемые на уровне сервиса |
Тип TraitItem:
| Поле | Тип | Описание |
| --- | --- | --- |
| trait_id | INTEGER | Ссылка на trait |
| is_required | BOOLEAN | Признак обязательности |
NB: Модели адресуются в контексте `traits`
@todo: Relationship restrictions.
@todo: Процедуры проверки PL/PGSQL.
## ServicePolicy
Групповые настройки сервисов. Аналог ***Profile в NOC, но единый для всех видов сущностей.
Предполагается, что для каждого ServiceType будет автоматически создаваться ServicePolicy с именем `<service_type> default`
Таблица БД: `main.service_category`
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| description | TEXT | NULL | Описание |
| service_type_id | INTEGER | NOT NULL REFERENCES service_type | ссылка на тип сервиса |
| workflow_id | INTEGER | NOT NULL REFERENCES workflow | Рабочий процесс |
| data | JSONB | NULL | Групповые настройки, модель описана в service_type.category_model |
| labels | ARRAY[TEXT] | NULL | Метки |
| effective_labels | ARRAY[TEXT] | NULL | Эффективный набор меток |
| mappings | JSONB | NULL | Отображения ID из внешних систем. Массив |
| > remote_system_id | INTEGER | | id RemoteSystem |
| > remote_id | TEXT | | id во внешней системе |
Все используемые labels должны иметь `permit` `service_policy`
@todo: Caps?
## Service
Сервисы. Вездесущая сущность, модель данных определяется настройками ServiceType
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| description | TEXT | NULL | Описание |
| service_category_id | INTEGER | NOT NULL REFERENCES service_category | Категория сервисов |
| data | JSONB | | Настройки сервисов, модель описана в service_type.service_model |
| labels | ARRAY[TEXT] | NULL | Метки |
| effective_labels | ARRAY[TEXT] | NULL | Эффективный набор меток |
| mappings | JSONB | NULL | Отображения ID из внешних систем. Массив |
| > remote_system_id | INTEGER | | id RemoteSystem |
| > remote_id | TEXT | | id во внешней системе |
Все используемые labels должны иметь `permit` `service`
NB: Организация иерархий определяется на уровне связей сервисов.
NB: data и category доступны из ORM через модели pydantic (lazy get) как поля .data и .category
NB: Для удобства работы и отчетов в системе создается набор view (`v_*`) и поля из `data` могут вытягиваться как отдельные аттрибуты view.
@todo: Caps?
## ServiceTopology
Связи между сервисами служат для выполнения различных задач
и могут быть сгруппированы по назначению. При разделении ребер
графа на несколько групп мы получаем разбиение общего графа на несколько независимых графов с разными свойствами. Каждый полученный граф называется "Топологией" и обладает отдельными свойствами и накладывает отдельные ограничения.
Предполагается, что ServiceTopology будет заполняться из коллекций через механизм ETL.
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| description | TEXT | NULL | Описание |
| is_acyclic | BOOLEAN | NOT NULL | Требование ацикличности |
Предопределенные топологии:
| Имя | is_acyclic | Описаниие |
| --- | --- | --- |
| `inventry` | Да | Иерархия inventory |
| `service_fault` | Да | распространение аварии по зависимостям |
| `l2_uplink` | Нет | корреляция аварий на основе топологии L2 |
## ServiceLinkType
Тип связей между сервисами (ребер графа).
Предполагается, что ServiceLinkType будет заполняться из коллекций через механизм ETL.
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| description | TEXT | NULL | Описание |
| topology_id | INTEGER | NOT NULL | Ссылка на ServiceTopology |
| from_type_id | INTEGER | NOT NULL | Тип узла для начала ребра |
| to_type_id | INTEGER | NOT NULL | Тип узла для окончания ребра |
## ServiceLink
Связь между сервисами (ребро графа).
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| id | INTEGER | NOT NULL PRIMARY KEY | Первичный ключ |
| name | VARCHAR | NOT NULL | UNIQUE | Название типа сервисов |
| link_type_id | INTEGER | NOT NULL | Тип связи |
| from_service_id | INTEGER | NOT NULL | Сервис начала ребра |
| to_service_id | INTEGER | NOT NULL | Сервис окончания ребра |
| mappings | JSONB | NULL | Отображения ID из внешних систем. Массив |
| > remote_system_id | INTEGER | | id RemoteSystem |
| > remote_id | TEXT | | id во внешней системе |
## ServiceStatus
Текущее состояние сервиса. Вынесено в отдельную таблицу, так как
часто обновляется и из-за MVCC Postgres будет приводить к распуханию и деградациии таблицы с сервисами.
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| service_id | INTEGER | NOT NULL UNIQUE PRIMARY | Ссылка на сервис |
| admin_status | INTEGER | NOT NULL | Административное состояние (бизнес). Назначается по state workflow |
| dep_status | INTEGER | NOT NULL | Вычисляемый статус по зависимостям |
| probe_status | INTEGER | NOT NULL | Результат работы пробы |
| op_status | INTEGER | NOT NULL | Операционное состояние. Результат композиции dep_status и op_status |
| admin_last_change | TIMESTAMP | NOT NULL | Время изменения admin_status |
| dep_last_change | TIMESTAMP | NOT NULL | Время изменения dep_status |
| probe_last_change | TIMESTAMP | NOT NULL | Время изменения probe_status |
| op_last_change | TIMESTAMP | NOT NULL | Время изменения op_status |
AdminState может принимать значения:
1. UNKNOWN - Не определено
2. PROVISIONING - В процессе настройке
3. FAIL - Ошибка при развертывании
4. READY - Готов
5. SUSPEND - Приостановлен
6. MAINTENANCE - Отключен на РНР
7. CLOSED - Закрыт, больше не используется
OpState может принимать значения:
1. NA - Не применимо
2. UNKNOWN - Не определено
3. DISABLED - Отключен
4. FAIL - Не работает
5. DEGRADED - Деградация. Еще один отказ, и будет авария.
6. SOFT DEGRADED - Есть отказ зависимости, но остается резерв.
7. OK - Работает, все зависимости - OK.
## Labels
Метки.
Таблица БД: `main.labels`
| Поле | Тип | Constraits | Описание |
| --- | --- | --- | --- |
| label | VARCHAR | NOT NULL | PRIMARY KEY | Название метки |
| description | TEXT | NULL | Описание |
| permit | ARRAY[TEXT] | NULL | Допустимые применения |
| expose | ARRAY[TEXT] | NULL | Фильтры перетекания |
Допустимые значения для permit и expose:
* `remote_system`
* `service_category`
* `service`
* `workflow`
* `state`
```mermaid
graph LR
RemoteSystem --> ServiceCategory
ServiceCategory --> Service
Workflow --> ServiceCategory
State --> Service
```
## @todo: Worflow
## @todo: State
## @todo: Agent
## @todo: RemoteSystem
## @todo: Project
## @todo: ServiceEvent
Схема: fm
## @todo: ServiceAlarm
Схема: fm
+root
+root_type
## @todo: ServiceMaintenanceCategory
## @todo: ServiceMaintenance
@todo: Workflow
## Вычисление effective_labels
Производится на уровне триггеров по диаграмме перетекания меток. Для того, чтобы метка перетекла по стрелке необходимо выполнение двух условий: наличие разрешений `expose` (право передать метку в направлении стрелки) и `permit` (право принять метку).
## Корреляция аварий по зависимостям
Осуществляется по топологии service_fault. Топология является ацикличной,
@todo: Резерв
@todo: РНР
## Корреляция по топологии L2
Корреляция проводится по топологии l2_uplink. Топология может содержать циклы и строится между Managed Object'ами с использованием связей типа "L2 Uplink"
```mermaid
graph LR
MO1 --> MO3
MO2 --> MO3
MO1 --> MO2
MO2 --> MO1
```
Авария считается последствием, если все ее зависимости накрыты аварией. В таком случае, она коррелируется с наиболее старой аварией.
@todo: Нужен ли виртуальный сервис L2?
## @todo: Корреляция по топологии L3
## Cases
### Happy Customer
Если сервисная модель ориентирована на обслуживание живых клиентов,
заказывающих одновременно несколько услуг, то можно использовать виртуальные сервисы типа Happy Customer. Клиент счастлив, когда у него все работает.
```mermaid
graph LR
Customer[Happy Customer]
Internet --> Customer
IPTV --> Customer
VoIP --> Customer
```
Сервисы типа Happy Customer могут строиться автоматически, группируя сервисы по признаку Customer.
## Открытые вопросы
Заполняйте свои вопросы здесь
*