---
# System prepended metadata

title: Channel Management (Path Based)

---

# Channel Management (Path Based)

## Resource

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

Состоит из 3 частей:

* Модель (в терминах NOC)
* id - идентификатор в модели
* path - опциональный путь внутри ресурса

Для кодирования ресурса можно использовать любое обратимое преобразование, которое позволяет:

* От записи в базе (или ее части) перейти к идентификатору ресурса
* От идентификатора ресурса перейти к записи в базе

Наиболее простым в работе будет кодирование в виде строки:

```
<код модели>:<id>[:path]
```

Коды модели берутся из таблицы:

| Код | Модель |
| --- | --- |
| `o` | inv.Object |

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

Примеры:

| Resource | Пример |
| --- | --- |
| `o:12345` | Объект с id 12345 |
| `o:12345:4` | Connection `4` объекта с id 12345 |

## Канальный ресурс

Ресурсы, которые могут использоваться для организации каналов называются "Канальными ресурсами"

## Python API

### Получение ресурса для модели/документа

В моделях/документах, которые могут использоваться как ресурсы реализуется протокол `AsResource`:

``` python
class AsResource(Protocol):
    def as_resource(self, path: Optional[str] = None) -> str: ...
```

Используется:

``` python
Object.get_by_id("xxxxx").as_resource()
Object.get_by_id("xxxxx").as_resource("3")
```

### Получение объекта

`noc.core.resource`

```
def from_resource(id:str) -> Tuple[Model|Document, Optional[str]]:...
```

## TechDomain

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

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

* id
* name
* code - короткий символьный код (`group`, ...)
* uuid
* description
* controller_handler
* allow_parent - разрешать родительские каналы
* allow_children - разрешать дочерние каналы
* allow_p2p - разрешить топологию p2p
* allow_up2p
* allow_bunch - ... bunch
* allow_p2mp -  ... p2mp
* allow_up2mp
* allow_star - ... star
* channel_discriminator - опционально - дискриминатор на уровне канала
* endpoint_discriminator - опицонально - дискриминатор для подключения к каналу

Из коробки система поставляется со следующими доменами:

* group - группировка канала
* optical_sm - оптика одномод
* optical_mm - оптика многомод
* otn_otu - Уровень OTN OTU
* otn_pdu - Уровень OTN ODU

## Channel

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

:::info
Вопрос о целесообразности более двух уровней иерархии каналов остается открытым.
:::

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

Каналы реализуют связность по одной из нескольких топологий:

* `p2p` - point to point, точка-точка
* `up2p` - unidirectional point to point, однонаправленная точка-точка
* `bunch` - множественная точка-точка. Состоит из независимых и связанных между собой пар ресурсов. Фактически является группировкой нескольких `p2p` каналов (пучок), без необходимости создания отдельного канала на каждую пару
* `ubunch` - однонаправленный `bunch`. Возможно движение строго от корней к листьям.
* `p2mp` - point to multipoint. дерево. Связность между листьями отсутсвует. Возможно движение от корня к листу или от листа к корню
* `up2mp` - unidirectional point to multipoint, однонаправленное дерево. Возможно движение строго от корня к листу.
* `star` - полносвязная топология.


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

* id
* name
* parent - родитель (если есть)
* tech_domain - ссылка на TechDomain
* description
* topology -  тип топологии (см. выше)
    * p2p
    * up2p
    * bunch
    * ubunch
    * p2mp
    * up2mp
    * up2mp
    * star
* kind - тип канала
    * l1
    * l2
    * l3
    * internet
* 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, который задействован в ограничении.

:::info
При задании ограничений можно и нужно использовать иерархичность ресурсов
:::

## Endpoint

По определению каналы начинаются и заканчиваются на каких-то ресурсах. Эти ресурсы отличаются от промежуточных ресурсов по пути. Во первых, они являются границами канала, то есть являются конечной целью всего процесса управлениия каналами. Во вторых - они позволяют другим каналам пользоваться связностью. Назовем их точками терминации или конечными точками.

В отдельных случаях каналы требуют раздельных физических сред для приема и передачи. В таком случае подключение возникает в 4 точках, которые должны быть разделены на 2 пары. Это решается кодом направления. Так как понятие "направление" весьма условно, используется "правило большого пальца":

* 0 - исходящее направление от того места, с которого мы начали строить канал
* 1 - входящее направление

Модель:

* id
* channel - указатель на канал, связывающий точки подключения
* resource - Resource
* is_root - корневой узел дерева для топологии p2mp
* pair - Для топологии `bunch` задает номер пары. Допускается не более 2 TP в канале с одной парой.
* used_by - коналы, использующие связность.

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

## ResourcePath

Для организации связности канальные ресурсы должны быть связаны между собой, образовывая граф. Граф просчитываеся заранее и связывает между собой все возможные ресурсы. Узлами графа являются ресурсы, дугами - возможная связность между ними. 

В случае, если ресурсы - объекты и их connection, дуги формируются из ObjectConnection и кроссировок объекта.

Аттрибутика для особых ресурсов уже размечена в структуре Endpoint.

Модель данных для дуг:

* x - resorce
* y - resource
* channels - список каналов, которые проходят через дугу

    * channel - id канала

## Пример OTN

``` mermaid
%%{}%%
graph LR
    1((1))
    2((2))
    subgraph ADM1
        ADM1::Client1[Client1]
        subgraph ADM1::SFP[Line1]
            ADM1::sfp_tx[tx]
            ADM1::sfp_rx[rx]
        end
        ADM1::Client1 -- odu::ODU2:ODU1-1 --- ADM1::SFP
    end
    subgraph OM1
        OM1::C14[C14]
        OM1::Line[Line]
        OM1::C14 --> OM1::Line
    end
    subgraph OD1
        OD1::C14[C14]
        OD1::Line[Line]
        OD1::Line -- lambda::c14 --> OD1::C14
    end
    subgraph Patch1
        Patch1::1[1]
        Patch1::2[2]
        Patch1::c[Cable]
        Patch1::1 -- fiber::1 --- Patch1::c
        Patch1::2 -- fiber::2 --- Patch1::c
    end
    subgraph Patch2
        Patch2::1[1]
        Patch2::2[2]
        Patch2::c[Cable]
        Patch2::1 -- fiber1::1 --- Patch2::c
        Patch2::2 -- fiber::2 --- Patch2::c
    end
    Patch1::c --- Patch2::c
    subgraph ADM2
        ADM2::Client5[Client5]
        subgraph ADM2::SFP[Line2]
            ADM2::sfp_tx[tx]
            ADM2::sfp_rx[rx]
        end
        ADM2::Client5 -- odu::ODU2:ODU1-1 --- ADM2::SFP
    end
    subgraph OM2
        OM2::C14[C14]
        OM2::Line[Line]
        OM2::C14 --> OM2::Line
    end
    subgraph OD2
        OD2::C14[C14]
        OD2::Line[Line]
        OD2::Line -- lambda:c14 --> OD2::C14
    end    
    1 --- ADM1::Client1
    2 --- ADM2::Client5
    ADM1::sfp_tx --> OM1::C14
    OM1::Line --> Patch1::1
    Patch2::1 --> OD2::Line
    OD2::C14 --> ADM2::sfp_rx
    ADM2::sfp_tx --> OM2::C14
    OM2::Line --> Patch2::2
    Patch1::2 --> OD1::Line
    OD1::C14 --> ADM1::sfp_rx
```

```graphviz
graph {
    graph [rankdir = LR]
    e1 [shape = point]
    e2 [shape = point]
    subgraph cluster_ADM1 {
      graph [ label="ADM1"]
      ADM1_Client1 [shape = box label = "Client 1"]
      ADM1_Line1 [shape = record label="<rx>rx|<out>Line1|<tx>tx"]
    }
    subgraph cluster_ADM2 {
      graph [ label="ADM2"]
      ADM2_Client5 [shape = box label = "Client 5"]
      ADM2_Line2 [shape = record label="<rx>rx|<out>Line2|<tx>tx"]
    }
    e1 -- ADM1_Client1
    e2 -- ADM2_Client5
    ADM1_Client1 -- ADM1_Line1:out [label="odu::ODU2:ODU1-1" style=dashed]
    ADM2_Client5 -- ADM2_Line2:out [label="odu::ODU2:ODU1-1" style=dashed]
    ADM1_Line1:tx -- ADM2_Line2:rx [label="C14" dir=forward]
    ADM2_Line2:tx -- ADM1_Line1:rx [label="C14" dir=forward]
}
```


Рассмотрим процесс организации канала по сети OTN от точки 1 к точке 2.

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

* Оптическая коммутация (Och)
* OTU Trail
* ODU Trail

**Och**
На нашей схеме изображены две патч-панели, соединеные кабелем. Для простоты мы используем только первых 2 порта, остальные опускаем, чтобы не загромождать схему.

Пользователь выбирает первый порт Patch1 и жмет на кнопку "Create channel"

Создаем оптический канал. Для оптических каналов идеальным типом топологии является `bunch`, так как его endpoint'ы образуют связанные пары. Это избавляет нас от необходимости создавать отдельные каналы на каждое волокно. Весь сегмент оптической сети после разварки может быть представлен как один канал.

Добавляем канал в справочник:

| id | tech_domain | kind | topology |
| --- | --- | --- | --- |
| ==Och1== | ==optical_sm== | ==L1== | ==bunch== |

Порты патч-панелей являются точками выхода из каналов.

Мы вызываем метод `prepare_channel` контроллера `optical_sm`, передавая ему как параметр первый порт патч-панели Patch1.

Контроллер проводит трассировку связности, используя object connection и, по необходимости, дискриминатор fiber. Дискриминатор fiber задает номер волокна.

В результате в таблице Endpoint добавляются записи

| channel | resource | pair | used_by |
| --- | --- | --- | --- |
| ==Och1== | ==o:Patch1:1== | ==1== | |
| ==Och1== | ==o:Patch1:2== | ==2== | |
| ==Och1== | ==o:Patch2:1== | ==1== | |
| ==Och1== | ==o:Patch2:2== | ==2== | |

Мы видим 4 endpoint'а, объединенные в 2 пары.

На схеме так же присутсвуют пассивные оптические устройства:

* Оптические мультиплексоры (OM) - собирают сигнал с клиентских портов в один линейный
* Оптические демультиплексоры (DM) - раскладывают входящий по линейному порту сигнал по клиентским портам по длинам волны.

Комбинация OM и OD позволяет использовать оптическое уплотнение.
Пара устройств OM и OD образуют однонаправленный канал. Для таких устройств удобнее всего использовать топологию `ubunch`, которая представляет собой однонаправленный вариант `bunch`.

Пользователь выбирает клиентский порт мультиплексора или демультиплексора и нажимает кнопку "Создать канал".

Контроллер проводит трассировку связности, используя object connection и, по необходимости, дискриминатор fiber. Дискриминатор fiber задает номер волокна. Если по пути встречаются endpoint'ы процедура проходит сразу к парному endpoint'у.

Так как у нас две пары мультиплексоров мы создаем два канала:

| id | tech_domain | kind | topology |
| --- | --- | --- | --- |
| Och1 | optical_sm | L1 | bunch |
| ==Och2== | ==optical_sm== | ==L1== | ==ubunch== |
| ==Och3== | ==optical_sm== | ==L1== | ==ubunch== |

Также создаются endpoint'ы для каждого из оптических каналов. Чтобы не загромождать таблицу мы показываем только канал 14 (пара 14).

| channel | resource | pair | is_root | used_by |
| --- | --- | --- | --- | --- |
| Och1 | o:Patch1:1 | 1 | | ==Och2== |
| Och1 | o:Patch1:2 | 2 | | ==Och3== |
| Och1 | o:Patch2:1 | 1 | | ==Och2== |
| Och1 | o:Patch2:2 | 2 | | ==Och2== |
| ==Och2== | ==o:OM1:C14== | ==14== | ==True== | |
| ==Och2== | ==o:OD2:C14== | ==14== | | |
| ==Och3== | ==o:OM2:C14== | ==14== | ==True== | |
| ==Och3== | ==o:OD1:C14== | ==14== | | |

Так как мы использовали промежуточный канал Och1, мы также заполняем поля used_by на его соответствующих endpoint.

**OTU Trail**

* Пользователь выбирает карту ADM1
* Контроллер находим список свободных линейных портов по следующему алгоритму:
    * поддерживаются протоколы OTU
    * resource порта не содержится в поле Endpoint.resource
    * если порт имеет direction in, проверяем, что он соединен.
* Пользователь выбирает порт/для всех портов и длину волны
* Если connection имеет тип inner, спускаемся к трансиверу
* Находим выходной порт (tx)
* Проходим по object connection, по необходимости используя дискриминаторы lambda и fiber пока не дойдем до слота, который поддерживает протоколы OTU или имеет connection type типа outer и парный слот поддерживает протоколы OTU.
* Повторяем процесс в обратную сторону пока не придем в исходный порт
* Берем пересечение списка протоколов OTU на портах с двух сторон
* Показываем пользователю парный порт и типы OTU
* Пользователь выбирает порт и тип OTU

Создаем канал:

| id | tech_domain | kind | topology | channel_discriminator |
| --- | --- | --- | --- | --- |
| Och1 | optical_sm | L1 | bunch |  |
| Och2 | optical_sm | L1 | ubunch |  |
| Och3 | optical_sm | L1 | ubunch |  |
| ==OTU1== | ==otn_otu== | ==L1== | ==p2p== | ==otu:OTU2, lambda:c14== |

Мы запомнили выбранный тип OTU и длину волны в канальном дискриминаторе.

Добавляем в endpoint'ы выбранные порты:

| channel | resource | pair | is_root | used_by |
| --- | --- | --- | --- | --- |
| Och1 | o:Patch1:1 | 1 | | Och2 |
| Och1 | o:Patch1:2 | 2 | | Och3 |
| Och1 | o:Patch2:1 | 1 | | Och2 |
| Och1 | o:Patch2:2 | 2 | | Och2 |
| Och2 | o:OM1:C14 | 14 | True | =={OTU1, direction=0}== |
| Och2 | o:OD2:C14 | 14 | | =={OTU1, direction=0}== |
| Och3 | o:OM2:C14 | 14 | True | =={OTU1, direction=1}== |
| Och3 | o:OD1:C14 | 14 | | =={OTU1, direction=1}== |
| ==OTU1== | ==o:ADM1:Line1== | | | |
| ==OTU1== | ==o:ADM2:Line2== | | | |

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

Контроллер создает два задания на настройку OTU на линейных картах

**ODU**

* Клиент выбирает клиентский порт
* Контроллер находит все каналы с типом otn_otu, которые выходят с линейных портов карты
* Для каждого из каналов контроллер находит:
    * список не занятых портов с протоколами ODU с другой стороны, на которые физически можно осуществить коммутацию
    * Свободные ODU
* Клиент выбирает ответный порт, тип ODU и место ODU в общем контейнере

Создаем новый канал:

| id | tech_domain | kind | topology | channel_discriminator |
| --- | --- | --- | --- | --- |
| Och1 | optical_sm | L1 | bunch |  |
| Och2 | optical_sm | L1 | ubunch |  |
| Och3 | optical_sm | L1 | ubunch |  |
| OTU1 | otn_otu | L1 | p2p | otu:OTU2, lambda:c14 |
| ==ODU1== | ==otn_odu== | ==L1== | ==p2p== | ==odu:ODU2:ODU1-1== |

Добавляем endpoint'ы:

| channel | resource | pair | is_root | used_by |
| --- | --- | --- | --- | --- |
| Och1 | o:Patch1:1 | 1 | | Och2 |
| Och1 | o:Patch1:2 | 2 | | Och3 |
| Och1 | o:Patch2:1 | 1 | | Och2 |
| Och1 | o:Patch2:2 | 2 | | Och2 |
| Och2 | o:OM1:C14 | 14 | True | {OTU1, direction=0} |
| Och2 | o:OD2:C14 | 14 | | {OTU1, direction=0} |
| Och3 | o:OM2:C14 | 14 | True | {OTU1, direction=1} |
| Och3 | o:OD1:C14 | 14 | | {OTU1, direction=1} |
| OTU1 | o:ADM1:Line1 | | | =={ODU1, disc=odu:ODU2:ODU1-1}== |
| OTU1 | o:ADM2:Line2 | | | =={ODU1, disc=odu:ODU2:ODU1-1}== |
| ==ODU1== | ==o:ADM1:Client1== |
| ==ODU1== | ==o:ADM2:Client5== |

Контроллер создает 2 кроссировки на линенйных картах
Контроллер отправляет задание на настройку кроссировок на ADM картах