---
# System prepended metadata

title: GUFO Data Model

---

# 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.


## Открытые вопросы

Заполняйте свои вопросы здесь

* 