# Привязка интерфейсов к физическим портам inventory
## Задача
Установить соответсвие между физическими портами, полученными через
asset discovery и из моделей устройств с логическими интерфейсами,
полученными через interface discovery.
## ConnectionType
В ConnectionType необходимо добавить дополнительный признак:
* is_physical_interface
Признак показывает, что в данном слоте находится физический интерфейс.
Такие слоты могут быть привязаны к логическим интерфейсам.
## iter_physical_interface
```
ManagedObject.iter_physical_interface() -> Iterable[PhysicalPath]
где:
PhysicalPath = Tuple[PathItem, *]
PathItem - namedtuple(object, connection_type, connection_name)
```
Итератор возвращает записи с полным физическим путем для каждого
интерфейса. Полный физический путь состоит из всех модулей, начиная с шасси, вплоть до конкретного порта.
Порты определяются по признаку `is_physical_interface`,
порты являются границей, на которой останавливается рекурсивный спуск.
По умолчанию считается, что порт начинается на дырке SFP, а не на оптических разъмах.
## Collator
Класс, осуществляющий привязку логических интерфейсов к физическим.
Должен реализовывать интерфейс:
```
class BaseCollator(object):
def __init__(self, **kwargs):
...
def collate(self, physical_path, interfaces):
# type: (PhysicalPath, Dict[str, Interface]) -> Optional[str]
```
Класс `Collator` должен наследоваться от `BaseCollator` и может дополнительно конфигурироваться через именнованные аргументы конструктора.
Экземпляр `Collator` создается один раз на весь процесс привязки в соотвествующем Job'е discovery. Таким образом разрешается хранение внутреннего состояния на весь процесс привязки.
Основным рабочим методом является `collate`, который принимает на вход полный физический путь порта (результат одного yield `iter_physical_interface`) и словарь интерфейсов, нуждающихся в привязке (нормализованное имя интерфейса -> Interface instance).
Метод `collate` возвращает имя логического интерфейса соответсвующего данному физическому пути, если привязка удалась, или None, если привязка не удалась.
## Цепочки Collator'ов
Collator'ы могут быть сгруппированы в цепочки. Каждый физический
порт прогоняется по цепочке, пока не будет получен ответ, отличный от None. Первый успешный ответ и будет использоваться в привязке.
## Конфигурирование Сollator'ов
Осуществляется аналогично аппликаторам. В класс профилей добавляются настройки:
* `interface_collators` - список из:
* имя handler, или
* (имя handler, настройки)
настройки - dict с аргументами для конструктора collator'а.
Получение эффективных настроек осуществляется методом профиля:
```
@classmethod
def iter_collators(cls, object)
# type: (ManagedObject) -> Iterable[BaseCollator]
```
может использоваться для тонкой настройки collator'ов в зависимости от платформы.
## Процесс привязки
После отработки `interface` и `asset` discovery.
Осуществляется в конце `asset` discovery.
* Получаем цепочку настроенных collator'ов через `iter_collators`
* Если она пуста - завершаем обработку
* Строим словарь логических интерфейсов `interfaces`
* по всем `path` из iter_physical_interfaces`
* по всем `collator` из цепочки `collator'ов`
* вызываем метод `collate(path, interfaces)`
* если вернулся не None
* осущесвляем привязку
* break
## Хранение привязки
Вводится новый тип `EmbeddedDocument` - ObjectConnectionData,
для хранения дополнительных данных по связям объектов.
Поля:
* `name` - имя `ObjectConnection` из модели
* `interface_name` - имя привязанного интерфейса (если есть)
* `interface_managed_object` - опциональная ссылка на ManagedObject, если интерфейсы внутри объекта могут принадлежать разным ManagedObject. По умолчанию - всегда пустой.
В дальнейшем в ObjectConnectionData могут появляться другие поля.
Также в структуре `Object` появляется поле:
* `connections` - список `ObjectConnectionData`
При заполнении привязок происходит синхронизация `ObjectConnectionData`, добавляются и редактируются необходимые записи, пустые записи удаляются.
## Доработка datastream managedobject
В разделе `asset.slots` добавляется дополнительный опциональный параметр `interface`.
## Stopper'ы
* Изменяется структура `ConnectionType`, целесообразно реализовывать после слияния репозитория коллекций с `master`