Как описать канал провайдера в NetBox, если известен только наш порт, а оборудование оператора недоступно
Классический тупик при заведении канала провайдера в NetBox: наш конец — известный порт на свитче, а что там у оператора за оборудование — коммутатор, медиаконвертер или вообще безымянная точка в облаке MPLS — неизвестно и, как правило, не наше дело. Показываю, что Circuit в NetBox официально поддерживает одностороннее описание, когда реально использовать ProviderNetwork, а когда просто оставить Z-сторону пустой.
Симптом: администратор пытается придумать несуществующее устройство провайдера
Заявка от трастовой компании «КапиталХранитель» (18 рабочих мест) пришла с формулировкой «неправильно заводим провайдеров в NetBox». У клиента два магистральных канала — основной оптический ввод и резервный через другого оператора — оба заведены в NetBox как объекты Site и Device, а вот дальше администратор застрял: чтобы протянуть кабель от своего пограничного маршрутизатора до чего-то на другом конце, интерфейс редактирования кабеля требовал указать второе устройство. Пришлось заводить фиктивный Device с именем вроде «ISP-router-unknown», без реальных данных — просто чтобы кабель к чему-то подключился. Через полгода в базе висели два таких «призрачных» устройства с почти одинаковыми именами, и новый инженер уже не мог сказать, какое из них к какому реальному каналу относится. Мы разворачиваем и донастраиваем NetBox для учёта инфраструктуры как раз с прицелом на такие грабли — раздел Circuits в NetBox для этого спроектирован отдельно от Devices и Cables, и выдумывать оборудование провайдера в нём не нужно.
Смешение двух разных сущностей — это и есть корень проблемы. Кабель (Cable) в NetBox соединяет два физических порта, которые оба принадлежат вам и видны в инвентаре: патч-панель, интерфейс коммутатора, разъём на медиаконвертере. Канал провайдера (Circuit) — это принципиально другая модель: она описывает не физический кабель между двумя вашими портами, а услугу связи, которую вы покупаете у оператора, и у которой вы видите только свой конец. Пытаться натянуть Circuit на модель Cable — и есть причина, по которой администратор начинает придумывать несуществующие маршрутизаторы провайдера.
Что такое Circuit и CircuitTermination: A/Z-окончания
Circuit в официальной документации NetBox определён как «a physical point-to-point data connection, typically used to interconnect sites» — физическое соединение точка-точка, обычно используемое для связи между площадками. У объекта Circuit есть провайдер (Provider), идентификатор канала у этого провайдера (Circuit ID, уникальный в рамках провайдера), тип (интернет, MPLS/VPN и так далее), статус (по умолчанию Planned, Provisioning, Active, Offline, Deprovisioning, Decommissioned; список можно расширить через FIELD_CHOICES), даты ввода и отключения, коммит-скорость (commit rate) в кбит/с и опциональное расстояние между концами с единицей измерения.
Сами точки подключения канала описываются отдельной моделью — CircuitTermination, и у одного Circuit их может быть не более двух: сторона A и сторона Z. Это жёсткое ограничение модели, а не рекомендация — большего числа окончаний у одного Circuit создать нельзя. У CircuitTermination, помимо стороны (term_side), есть поле port_speed (скорость интерфейса в кбит/с), отдельное поле upstream_speed — если скорость асимметричная, как у кабельного модема, xconnect_id — идентификатор кросс-коннекта в дата-центре, mark_connected — булев флаг «считать подключённым» без требования реального кабеля, поле «Patch Panel & Port(s)» — чтобы записать патч-панель и порт на кроссе, не моделируя их отдельно, и связь cable — если этот конец канала физически подключён кабелем к вашему оборудованию.
Ключевое поле — termination: начиная с NetBox 4.2 (релиз 4.2.0 вышел 6 января 2025 года, issue #9604) это единый generic foreign key, который может указывать на Region, SiteGroup, Site, Location или ProviderNetwork. До 4.2 у CircuitTermination было два отдельных поля — site и provider_network, и это разделение создавало путаницу с тем, какое из них заполнять. Объединение в одно поле termination — не косметика: оно явно фиксирует, что сторона канала может быть либо точкой в вашей топологии (сайт, площадка, регион), либо абстрактной сетью провайдера — но это одно и то же по смыслу поле, просто с разным типом ссылки.
Главный ответ: Circuit с одной стороной — законный, задокументированный паттерн
Прямой ответ на вопрос «что делать, если известен только наш порт»: заводить только А-сторону CircuitTermination, а Z-сторону не заполнять вообще. Это не хак и не обход ограничений интерфейса — участник обсуждения на GitHub (discussion #17402 в основном репозитории netbox-community/netbox) сформулировал это предельно ясно: «You can have a circuit with a termination at one end but not the other» — можно иметь канал с окончанием на одном конце, но не на другом. Формы создания Circuit и CircuitTermination в NetBox не требуют обязательного заполнения обеих сторон — вы вводите провайдера, Circuit ID, тип и статус канала, затем создаёте ровно одну CircuitTermination на стороне A, привязанную к вашему Site (и, если нужно, к конкретному интерфейсу через Cable), и на этом можно остановиться.
В том же обсуждении другой участник, который сам работает в ISP и активно использует Circuits для кросс-коннектов в ЦОД, DSL и сотовых каналов, сделал важную оговорку: «they're billable items and procured from a provider» — то есть Circuit — это услуга, купленная у оператора, у них есть коммерческая сторона (счета, SLA, договор), которая никак не связана с физическим устройством на том конце. NetBox сознательно не требует описывать инфраструктуру оператора, потому что вы её не видите и не администрируете — и не должны пытаться её угадывать.
Второй вариант из того же обсуждения — использовать патч-панель (Device типа patch panel) как демаркационную точку, если у вас есть физическая точка сдачи-приёмки (кросс-коннект в дата-центре, распределительный щиток), где кабель провайдера физически подключается к вашей инфраструктуре. Это не альтернатива Circuit, а дополнение: сам канал по-прежнему описывается объектом Circuit с одной или двумя терминациями, а патч-панель — это устройство, к которому физически подходит кабель на вашей стороне, если такая точка у вас реально есть и вы её обслуживаете.
Практическая причина, почему это решение не выглядит очевидным с первого взгляда: интерфейс создания кабеля (Cable) в NetBox действительно просит указать оба конца, и по инерции кажется, что то же самое требование распространяется на Circuit целиком. Но Circuit и Cable — независимые сущности с разными правилами заполнения. Cable обязательно соединяет две реально существующие конечные точки, потому что кабель физически существует с двух сторон. CircuitTermination же можно создать в одном экземпляре, и уже к ней, если нужно, привязать Cable до вашего физического порта — при этом сама модель Circuit ничего не требует от второй стороны, потому что вторая сторона физически может быть вам вообще не видна.
Когда всё же нужен ProviderNetwork
ProviderNetwork — это отдельная модель именно для случая, когда дальний конец канала не пустой, а известный, но не детализируемый: вы знаете, что канал приходит в сеть провайдера, но что там внутри — маршрутизаторы, коммутаторы, топология — вам либо неизвестно, либо несущественно для ваших задач учёта. Официальная документация приводит характерный пример: региональная MPLS-сеть провайдера, к которой подключено сразу несколько ваших каналов — эта сеть и есть ProviderNetwork, общая точка Z для всех каналов, которые в неё приходят.
У модели ProviderNetwork три содержательных поля: Provider — привязка к оператору, ответственному за эту сеть, Name — уникальное в рамках провайдера человекочитаемое имя (например «Ростелеком MPLS Москва»), и Service ID — произвольный идентификатор, используемый как альтернативная ссылка на тип связности (может совпадать с внутренним кодом услуги у провайдера, а может быть придуман вами для удобства). Ничего похожего на модель устройства с интерфейсами — ProviderNetwork описывает именно сеть как единую точку, а не набор портов.
Разница между «оставить Z пустым» и «завести ProviderNetwork» — это разница между «неизвестно и не нужно» и «известно, но нам это не устройство, а сеть». Если у вас один канал в конкретную региональную MPLS-сеть провайдера и вы вряд ли когда-нибудь заведёте туда второй канал — можно обойтись и без ProviderNetwork, просто оставив Z-сторону незаполненной, разница на практике будет чисто декларативной. Но если у вас пять каналов от разных площадок сходятся в одну и ту же MPLS-сеть одного провайдера, ProviderNetwork стоит завести один раз и подключить к нему все пять CircuitTermination стороной Z — тогда в NetBox сразу видно, какие каналы логически связаны общей точкой провайдера, и при аварии в этой сети вы одним запросом поднимаете все пострадавшие каналы — та же логика, что я закладываю при настройке резервного канала с автоматическим переключением: сначала понять зависимость каналов друг от друга, потом уже настраивать реакцию на аварию.
Кейс «КапиталХранитель»: как я перезавёл два канала
У «КапиталХранителя» было два канала — основной оптический интернет-ввод от одного провайдера и резервный канал с автопереключением от другого, оба заведены как Circuit с фиктивными Device на стороне Z, придуманными администратором «для полноты картины». Первым шагом я удалил обе фиктивные записи устройств вместе с фиктивными кабелями к ним и пересобрал CircuitTermination заново: сторона A для обоих каналов — конкретные интерфейсы на пограничном маршрутизаторе клиента, привязанные Cable к реальным портам, сторона Z — не заполнена вообще, потому что ни один из двух провайдеров не был MPLS-сетью с несколькими подключениями клиента, просто два обычных интернет-ввода без видимости на инфраструктуру оператора.
Отдельно уточнил у клиента по договорам оба Circuit ID — у основного провайдера это оказался буквенно-цифровой номер договора вида «INET-2024-0847», у резервного — внутренний код услуги, который раньше просто не был записан нигде, кроме бумажного счёта. Занёс оба значения в поле Circuit ID, заполнил commit rate по факту тарифа (100 Мбит/с и 50 Мбит/с) и проставил статус Active обоим. Отдельно завёл третий Circuit — тестовый канал до дата-центра, где клиент арендует стойку под резервный сервер: этот канал реально приходит в MPLS-сеть провайдера дата-центра, к которой в перспективе подключится ещё один офис клиента с отдельным VLAN под серверный сегмент, поэтому для него я завёл ProviderNetwork «MPLS <провайдер ЦОД>, Москва» и привязал к нему сторону Z.
Вся работа заняла около трёх часов: час на разбор существующей путаницы с фиктивными устройствами и сверку договоров, час на пересборку двух простых каналов без Z-стороны, и час на третий канал с ProviderNetwork, включая проверку через API, что оба типа терминации (пустая Z и Z с ProviderNetwork) корректно отображаются в топологии. После этого в базе осталось ровно три объекта Circuit, ноль фиктивных устройств провайдеров и один ProviderNetwork, к которому в будущем можно будет добавлять новые каналы без пересборки существующих.
Ограничения модели, о которые легко споткнуться
Первое: физический Circuit нельзя завершить на LAG-интерфейсе (агрегированном канале). Документация CircuitTermination прямо ограничивает физическое подключение только реальным физическим интерфейсом, исключая виртуальные типы вроде LAG. Если у вас на площадке два физических канала от одного провайдера объединены в агрегацию на вашей стороне, в NetBox это моделируется как два отдельных Circuit, каждый со своей физической CircuitTermination на отдельный физический интерфейс — а сама агрегация описывается уже на уровне интерфейсов устройства (LAG-интерфейс, к которому привязаны оба физических), а не на уровне Circuit. Пытаться привязать Cable от CircuitTermination напрямую к виртуальному LAG-интерфейсу система не позволит.
Второе: для топологий с несколькими точками подключения к одному каналу (не путать с двумя сторонами A/Z одного канала) документация рекомендует моделировать каждую ветку («leg») отдельным Circuit, где один конец обычно приходит в инфраструктуру провайдера — то есть многоточечные конфигурации вроде MPLS с несколькими подключёнными офисами превращаются в набор двухсторонних Circuit, у каждого из которых Z-сторона — это один и тот же ProviderNetwork. Именно для этого случая ProviderNetwork и существует: он даёт общую точку сборки для набора формально независимых объектов Circuit.
Третье, менее очевидное: raw-модель NetBox не проверяет коммерческую логику — она не запретит вам создать Circuit без единой CircuitTermination вообще, просто такой канал будет виден только в списке Circuits и карточке провайдера, а трассировка кабеля (Trace) от вашего интерфейса до него не дойдёт. Если цель — не просто зафиксировать факт существования договора, а получить пользу от связей (трассировка от порта до канала при аварии, выгрузка через API для мониторинга), минимум одна CircuitTermination — сторона A на вашей стороне — обязательна.
И последнее по счёту, но не по значимости: поле port_speed у CircuitTermination — это скорость интерфейса, а не гарантированная провайдером полоса. Для этого у самого Circuit есть отдельное поле commit_rate — коммит-скорость по договору, обычно она меньше физической скорости порта (например, оптический порт на 1 Гбит/с при коммите 100 Мбит/с). Путать эти два поля — частая ошибка при первом заведении канала: администратор вписывает в commit_rate скорость интерфейса, и потом графики утилизации во внешнем мониторинге, который берёт полосу из NetBox, выглядят так, будто клиент использует канал на 10 % от ёмкости, хотя на деле упирается в честный коммит по договору.
Частые вопросы
Обязательно ли заполнять обе стороны Circuit — A и Z?
Нет. NetBox официально поддерживает Circuit с заполненной только стороной A — это подтверждено в обсуждении сообщества (discussion #17402): «можно иметь канал с окончанием на одном конце, но не на другом». Если дальний конец канала вам не виден и не принадлежит вам, Z-сторону можно оставить пустой.
Чем ProviderNetwork отличается от простого пустого Z-конца?
Пустой Z-конец означает «дальняя сторона неизвестна и неважна». ProviderNetwork — это когда дальняя сторона известна как сеть провайдера (например, региональная MPLS), но её внутреннее устройство неважно. ProviderNetwork имеет смысл заводить, когда к одной и той же сети провайдера подключено или будет подключено несколько ваших каналов — тогда это общая точка сборки для их всех.
Можно ли завершить Circuit на LAG-интерфейсе?
Нет, физическая CircuitTermination подключается кабелем только к физическому интерфейсу. Если несколько физических каналов от провайдера объединены агрегацией на вашей стороне, в NetBox каждый физический канал заводится отдельным Circuit на отдельный физический интерфейс, а агрегация описывается на уровне LAG-интерфейса устройства, не на уровне Circuit.
Нужно ли заводить фиктивное устройство провайдера, чтобы протянуть кабель до канала?
Нет, и делать так не стоит — это и есть типичная ошибка, которую разбирает статья. Cable в NetBox соединяет ваш физический порт непосредственно с CircuitTermination, без необходимости в промежуточном фиктивном устройстве на стороне провайдера.
С какой версии NetBox поле termination заменило site и provider_network у CircuitTermination?
С версии 4.2, вышедшей 6 января 2025 года. До этого у CircuitTermination было два отдельных foreign key поля — site и provider_network; их объединили в единое generic foreign key поле termination, которое может ссылаться на Region, SiteGroup, Site, Location или ProviderNetwork.
Что делать, если у нас есть физическая демаркационная точка — патч-панель в дата-центре?
Патч-панель заводится как отдельный Device (с фронтальными и тыльными портами) на вашей стороне, а сам канал провайдера по-прежнему описывается объектом Circuit. Если моделировать кросс не нужно, у CircuitTermination есть поля Cross-connect ID и Patch Panel & Port(s) — в них достаточно записать номер кросс-коннекта и порт.
Источники
- GitHub — netbox-community/netbox, docs/models/circuits/circuittermination.md — До двух окончаний A/Z; подключение только к физическому интерфейсу, не к LAG; multi-point — отдельный Circuit на каждую ветку с концом в ProviderNetwork; поля Termination (заменило site/provider_network в 4.2), Port/Upstream Speed, Cross-connect ID, Patch Panel & Port(s), Mark Connected: https://github.com/netbox-community/netbox/blob/main/docs/models/circuits/circuittermination.md
- NetBox Labs Docs — Provider Networks — Назначение ProviderNetwork, поля Provider/Name/Service ID, пример региональной MPLS-сети с несколькими подключёнными каналами: https://netboxlabs.com/docs/netbox/models/circuits/providernetwork/
- GitHub Discussion #17402, netbox-community/netbox — candlerb: «You can have a circuit with a termination at one end but not the other»; ross-cello (работает в ISP): патч-панель как точка демаркации и оговорка «they're billable items and procured from a provider»: https://github.com/netbox-community/netbox/discussions/17402
- GitHub — netbox-community/netbox, docs/models/circuits/provider.md и circuit.md — Поля модели Provider (name, slug, asns, portal_url, noc_contact, admin_contact) и модели Circuit (provider, cid, type, status, install_date, termination_date, commit_rate, distance): https://github.com/netbox-community/netbox/blob/main/docs/models/circuits/provider.md и https://github.com/netbox-community/netbox/blob/main/docs/models/circuits/circuit.md
- NetBox Labs Docs — Release Notes, версия 4.2 — Дата релиза 4.2.0 — 6 января 2025 года, breaking change: замена полей site и provider_network на единое generic foreign key поле termination у CircuitTermination: https://netboxlabs.com/docs/netbox/release-notes/version-4.2
- NetBox Labs — Zero To Hero 10: Providers and Circuits — Официальный учебный цикл NetBox Labs: заведение Provider, Circuit Type, Circuit и терминаций на практике: https://netboxlabs.com/zero-to-hero-10-providers-and-circuits/



