---
# System prepended metadata

title: Channel/Trail data model v3

---

# Channel/Trail data model v3

## Resource

Структура - умный указатель на ресурс в inventory. Не хранится сам по себе, но входит в состав других моделей.

Состоит из полей:

* model - имя модели (inv.Object, sa.Interface)
* id - Id - динамическое поле с типами int или ObjectId
* path - опциональный путь внутри ресурса

Поля oid и id взаимоисключающие и зависят от модели:

* id используется для типа int и данных в postgres
* oid используется для ObjectId и данных в mongo

**Пример1:** Точка присутсвия

``` json
{
    "model": "inv.Object",
    "id": `id объекта`
}
```

**Пример2:** Порт 4 на линейной карте

``` json
{
    "model": "inv.Object",
    "id": `id линейной карты`,
    "path": "4"
}
```

**Пример3:** Интерфейс

@todo: Уточнить

``` json
{
    "model": "inv.Interface",
    "id": `id интерфейса`
}
```

## TechDomain

Технологический домен, представляет собой технологию для организации связи и тесно связан с контроллером - технической реализацией процесса автоматизации.

Модель данных:

* id
* name
* uuid
* description
* controller_handler

Вопросы:

* Прочая аттрибутика

## Channel

Канал обеспечивает связность между специальными ресурсами, называемыми Channel Endpoint (точки подключения). Каналы могут образовывать иерархию. В случае иерархической схемы каналы-листья организовывают связность в пределах одного технологического домена, в то время как каналы-узлы их просто группируют. В таком случае у каналов-узлов технологический домен всегда равен `group`.

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

Модель данных:

* id
* name
* parent - родитель (если есть)
* description
* state
* labels
* effective_labels
* project
* subscriber
* supplier
* remote_system
* remote_id
* bi_id
* context - контекст контроллера
* constraints - клиентские настройки, ограничивающие возможные варианты построения. Список:
    * type - тип ограничения:
        * `i` - include
        * `e` - exclude
    * strict - boolean. Если `True`, то ограничение всегда должно соблюдаться, если `False`, то соблюдение условия желательно, но невозможность соблюдения не является фатальной.
    * resource - Resource, который задействован в ограничении.
* path - просчитанный граф ресурсов, необходимый для организации канала. Список:
    * x - Resource
    * y - Resource

## ChannelEndpoint

Точки подключения являются ресурсами, обозначающие места входа в канал и могут использоваться для одного или нескольких подключений других каналов.


Модель:

* id
* trail - указатель на канал, связывающий точки подключения
* tech_domain - ссылка на tech_domain
* resource - Resource
* is_root - корневой узел дерева для топологии p2mp
* used_by - коналы, использующие связность.

    * channel - указатель на channel
    * discriminator - опциональный дискриминатор, в случае, если точка подключения используется не монопольно.

## Пример

OTN:

``` mermaid
flowchart LR
    subgraph ADM1
        ADM1::Client1[[Client1]]
        ADM1::Line1[[Line1]]
        ADM1::Client1 -.- ADM1::Line1
    end
    subgraph Och
        subgraph Patch1
            Patch1::1[[1]]
        end
        subgraph Patch2
            Patch2::7[[7]]
        end
        Patch1::1 --- Patch2::7
    end
    subgraph ADM2
        ADM2::Client5[[Client5]]
        ADM2::Line4[[Line4]]    
        ADM2::Client5 -.- ADM2::Line4
    end
    ADM1::Line1 --- Patch1::1
    ADM2::Line4 --- Patch2::7
```

Для реализации схемы необходимо:
1. Реализовать оптическую связность (Och) между патч-панелямии
2. Реализовать OTU Trail между Line портами ADM-карт
3. Реализовать ODU Trail между Client портами ADM-карт

**Och Trail:**

Начнем с реализации Och trail.

После реализации топологической связности в inventory создаем канал.

Channel:
``` json
{
    "id": `och_trail`,
    "tech_domain": `optical`,
    "topology": "p2p",
    "path": [
        {
            "x": {
                "model": "inv.Object",
                "id": `Patch1`,
                "path": "1"
            },
            "y": {
                "model": "inv.Object",
                "id": `Patch2`,
                "path": "7"                
            }
        }
    ]
}
```

Так как оптический канал предоставляет связность между двумя ресурсами мы создаем 2 endpoint.

ChannelEndpoints:

``` json
[
    {
        "trail": `och_trail`,
        "tech_domain": `optical`,
        "resource": {
            "model": "inv.Object",
            "id": `Patch1`,
            "path": "1"            
        }
    },
    {
        "trail": `och_trail`,
        "tech_domain": `optical`,
        "resource": {
            "model": "inv.Object",
            "id": `Patch1`,
            "path": "1"            
        }
    }
]
```

Далее мы используем оптический канал для реализации OTU trail.

Channel:
``` json
{
    "id": `otu_trail`,
    "tech_domain": `otn_otu`,
    "topology": "p2p",
    "path": [
        {
            "x": {
                "model": "inv.Object",
                "id": `ADM1`,
                "path": "Line1"
            },
            "y": {
                "model": "inv.Object",
                "id": `Patch1`,
                "path": "1"                
            }
        },
        {
            "x": {
                "model": "inv.Object",
                "id": `ADM2`,
                "path": "Line4"
            },
            "y": {
                "model": "inv.Object",
                "id": `Patch2`,
                "path": "7"                
            }
        },
    ]
}
```

Так как у нас появилось два связных ресурса по технологии OTU мы добавляем два endpoint:

ChannelEndpoint
``` json
[
    {
        "trail": `otu_trail`,
        "tech_domain": `otn_otu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM1`,
            "path": "Line1"            
        }
    },
    {
        "trail": `otu_trail`,
        "tech_domain": `otn_otu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM2`,
            "path": "Line4"            
        }
    }
]
```

Так как наш OTU монопольно использует Och, мы добавляем OTU в точки подключения OCh в поля used_by и они становятся:

``` json
[
    {
        "trail": `och_trail`,
        "tech_domain": `optical`,
        "resource": {
            "model": "inv.Object",
            "id": `Patch1`,
            "path": "1"            
        },
        "used_by": [
            {
                "channel": `otu_trail`
            }
        ]
    },
    {
        "trail": `och_trail`,
        "tech_domain": `optical`,
        "resource": {
            "model": "inv.Object",
            "id": `Patch1`,
            "path": "1"
        },
        "used_by": [
            {
                "channel": `otu_trail`
            }
        ]
    }
]
```

Теперь мы видим, что порты патч-панели уже заняты.

Далее мы создаем ODU Trail, используя OTU.

Channel:

``` json
{
    "id": `odu_trail`,
    "tech_domain": `otn_odu`,
    "topology": "p2p",
    "path": [
        {
            "x": {
                "model": "inv.Object",
                "id": `ADM1`,
                "path": "Client1"
            },
            "y": {
                "model": "inv.Object",
                "id": `ADM1`,
                "path": `Line1"                
            }
        },
        {
            "x": {
                "model": "inv.Object",
                "id": `ADM2`,
                "path": "Client4"
            },
            "y": {
                "model": "inv.Object",
                "id": `ADM2`,
                "path": `Client5"                
            }
        },
    ]
}
```

У нас снова возникает два endpoint, на этот раз - клиентские порты:

``` json
[
    {
        "trail": `odu_trail`,
        "tech_domain": `otn_odu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM1`,
            "path": "Client1"            
        }
    },
    {
        "trail": `odu_trail`,
        "tech_domain": `otn_odu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM2`,
            "path": "Client5"            
        }
    }
]
```

Так как мы задействовали endpoint'ы OTU, мы должны на них прописать наш новый канал:

``` json
[
    {
        "trail": `otu_trail`,
        "tech_domain": `otn_otu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM1`,
            "path": "Line1"            
        },
        "used_by": [
            {
                "channel": `odu_trail`,
                "discriminator": "odu::ODU2::ODU1-1"
            }
        ]
    },
    {
        "trail": `otu_trail`,
        "tech_domain": `otn_otu`,
        "resource": {
            "model": "inv.Object",
            "id": `ADM2`,
            "path": "Line4"            
        },
        "used_by": [
            {
                "channel": `odu_trail`,
                "discriminator": "odu::ODU2::ODU1-1"
            }
        ]
    }
]
```

Мы также должны добавить задания на кроссировки:

ADM1:

``` json
{
    "input": "Client1",
    "output": "Line1",
    "output_discriminator": "odu::ODU2::ODU1-1"
}
```

ADM2:
``` json
{
    "input": "Client5",
    "output": "Line4",
    "output_discriminator": "odu::ODU2::ODU1-1"
}
```


Теперь решаем задачи:

**Найти канал, начинающийся с ADM1::Client1**

```
channelendpoints.find(
    {
        "resource": {
            "$elemMatch": {
                "model": "inv.Object",
                "id": `ADM1`,
                "path": "Client1"            
            }
        }
        
        
    }, {'channel': 1})
```

**Найти каналы, проходящий через Patch1::1**

```
channels.find(
    {
        "$or": [
            "path.x": {
                "$elemMatch": {
                    "model": "inv.Object",
                    "id": `Patch1`,
                    "path": "1"
                }
            },
            "path.y": {
                "$elemMatch": {
                    "model": "inv.Object",
                    "id": `Patch1`,
                    "path": "1"
                }
            }
        ]
    }, {"_id": 1, "used_by": 1}
)
```

Запоминаем id, и все id из used_by

```
channels.find(
    {
        id: {
            "$in": <список id из used by>
        }
    }, {"used_by": 1}
)
```

Далее дополняем наш список id и смотримы новые used by. Повторяем рекурсивно с новыми used by пока не остановимся.


**Найти свободные ODU на ADM1::Line1**

```
channelendpoints.find(
    {
        "resource": {
            "$elemMatch": {
                "model": "inv.Object",
                "id":  `ADM1`,
                "path": "Line1"
            }
        }
    }, {"used_by": 1}
)
```

Анализируем поля `discriminator`

@todo: Где взять настроенный тип OTU?


## Старый хлам

## Создание ODU Trail

1. Пользователь выбирает домен OTU
2. Пользователь выбирает группу в inventory (город, PoP, стойку, шасси, карту)
3. Контроллер находит все вложенные объекты
4. Контроллер выбирает все модели из списка объектов
5. Итератор выдает возможные точки подключения в виде (model=inv.Object, resource_id=<id>, path=<имя слота>, hints=<список поддерживаемых ODU>) для всех connections, которые поддерживают протоколы ODU*
6. Из полученного списка отфильтровываются все записи, которые уже присутсвуют в termination points (поля tech_domain, model, resource_id, path)
7. Пользователю предлагается список портов с доступными типами ODU
8. Пользователь выбирает порт и тип ODU
9. Контроллер проверяет все исходящие OTU Trail с данной карты и возвращает список: (OTU Trail, *список свободных портов, поддерживающих данный ODU*). Поиск осуществляется по termination point, домену==OTN OTU, model =inv.Object, resource_id=(текущая карта)
10. Если нет подходящего OTU, пользователь переходит к созданию OTU Trail
11. Пользователь выбирает ответный порт и место OTU в ODU
12. Контроллер создает запись в channel
13. Контроллер создает 2 trail с типом OTU (левый и правый) и привязывает их к каналу
14. Контлоллер создает 2 termination point для клиентских портов и привязывает их к левому и правому trail
15. Контроллер находит termination point'ы для выбранного OTU и прописывает им в endpoint ODU trail'ы и дискриминатор
16. Контроллер запускает группу из двух заданий на настройку кроссировки на ADM
                                                            

## Создание OTU Trail

1. Пользователь выбирает домен OTU
2. Пользователь выбирает группу в inventory (город, PoP, стойку, шасси, карту)
3. Контроллер находит все вложенные объекты
4. Контроллер выбирает все модели из списка объектов
5. Итератор выдает возможные точки подключения в виде (model=inv.Object, resource_id=<id>, path=<имя слота>, hints=<список поддерживаемых OTU>) для всех connections, которые поддерживают протоколы OTU*
6. Из полученного списка отфильтровываются все записи, которые уже присутсвуют в termination points (поля tech_domain, model, resource_id, path)
7. Пользователю предлагается список портов с доступными типами OTU

Далее необходимо выбрать ответную часть.
    
Если существующая топология позволяет построить путь от выделенного порта к другому порту, поддерживающему выбранный тип OTU, то предлагаем соответсвующий порт.
    
В противном случае переходим к процедуре создания оптического канала Och
    

## Создание оптического канала


Без ROADM:
    
1. Выбираем стартовую точку (как в предыдущих шагах)
2. Проходим по кроссировке и показываем конечную точку
    по необходимости руками меняем линки и кроссировки
3. Если нет ROADM пользователь фиксирует конечные точки
4. Если попался ROADM выбираем выходной порт и повторяем с пп. 2
5. Создается trail с доменом Optical
6. Создается 2 termination point с дискриминаторами lambda (может быть как фильтр)
7. Создаются задания на настройку ROADM

