Как перенести проверки качества данных из NetBox Reports в Custom Scripts и сохранить историю запусков
Reports в NetBox объявлены устаревшими ещё в версии 4.0: при апгрейде записи об отчётах превращаются в Scripts с сохранением истории, но ваш Python-код остаётся на совместимом классе Report, и переписывать его придётся руками. Ниже — что именно меняется в коде, куда девается история запусков и почему в 4.7 на замену нужно смотреть ещё раз.
Почему Reports устарели и что происходит при апгрейде
Reports были в NetBox отдельным типом объектов — Python-скриптами с ограниченным API, которые считали количество несоответствий в данных и не запрашивали у пользователя никаких параметров. Начиная с NetBox v4.0 (релиз 6 мая 2024 года) функциональность Reports официально объявлена устаревшей и объединена с Custom Scripts: документация формулирует это как «Reports are deprecated beginning with NetBox v4.0, and their functionality has been merged with custom scripts». В release notes 4.0.0 это звучит жёстче — «legacy reports функциональность удалена», а существующие отчёты автоматически конвертируются в скрипты при апгрейде. Когда я веду внедрение NetBox для компании, которая уже писала свои Reports на старых версиях, я всегда предупреждаю: автоконвертация решает не всё, особенно если в отчёте была нестандартная логика запуска.
Хорошая новость: история запусков не теряется. Документация прямо гарантирует — «previous job history will be retained» — прошлые задания видны и после конвертации. Но важно понимать, что именно конвертируется. NetBox переносит записи в базе: модули отчётов становятся модулями скриптов, задания остаются на месте. Сам Python-файл никто не переписывает — в нём по-прежнему from extras.reports import Report, и работает он только потому, что в ядре оставлен совместимый класс Report со старыми сигнатурами логирования. Документация честно предупреждает: поддержка legacy reports будет удалена в одном из будущих релизов. Поэтому код нужно переносить самому, и ломается он как раз в момент ручной правки — об этом дальше.
Что меняется в коде: импорты, базовый класс, логирование
Первое, что нужно поменять руками, — импорт и базовый класс. Было: from extras.reports import Report и class MyReport(Report):. Стало: from extras.scripts import Script и class MyReport(Script):. Это не просто переименование — Script умеет то, чего не было у Report: запрашивать параметры у пользователя перед запуском через типизированные переменные (StringVar, IntegerVar, ObjectVar, ChoiceVar и другие) и явно коммитить или не коммитить изменения в базу через флаг commit. Запуск по расписанию, кстати, был и у Reports начиная с 3.x, так что это не повод для переезда.
Второе изменение тише, но именно оно чаще всего ломает перенесённые отчёты — сигнатура методов логирования. В Report было log_failure(obj, message): сначала объект, потом сообщение. В Script порядок обратный: log_failure(message=None, obj=None), объект стал необязательным вторым параметром. Пока класс остаётся Report, совместимая обёртка сама переставляет аргументы. Стоит сменить родителя на Script и не тронуть позиционные вызовы — сообщение и объект меняются местами: ошибки выполнения нет, но в журнале вместо текста проблемы стоит имя устройства, а ссылка на объект пропадает. Плюс у Script нет общего метода log() — документация предлагает заменить его на log_info(). Поэтому при миграции я первым делом ищу все вызовы log, log_success, log_failure, log_info, log_warning, log_debug и перевожу их на именованные аргументы.
from extras.scripts import Script
class ValidateAddressPlan(Script):
class Meta:
name = "Проверка адресного плана"
description = "Ищет префиксы без описания и устройства без серийного номера"
def run(self, data, commit):
self.log_info(message="Запуск проверки адресного плана")
# после смены родителя на Script вызов log_failure(obj, message)
# молча перепутает аргументы —
# нужно log_failure(message=..., obj=...)После такой правки старая логика отчёта продолжает работать, но уже с корректным порядком аргументов, а не с тем, что досталось в наследство от класса Report.
Тестовые методы: как раньше и как теперь
В Custom Scripts, как и в Reports до них, есть методы с префиксом test_ — например, test_prefixes_have_description или test_devices_have_serial. Документация подтверждает: методы, начинающиеся с test_, запускаются автоматически при выполнении скрипта, если не переопределён run(). Это унаследованный от Reports способ структурировать проверки — каждая логическая проверка в своём методе, а не одним длинным run().
Ловушка в том, что если вы всё же переопределяете run() собственной логикой — а в перенесённом коде это случается часто, когда рядом с проверками хочется добавить подготовку данных или фильтр по параметру, — тестовые методы test_* сами по себе больше не вызываются. Их нужно явно запустить через run_tests() внутри вашего run(). То же касается pre_run() и post_run(): их вызывает стандартный run(), а в переопределённом за них отвечаете вы. Я видел миграции, где все test_* остались в классе, но перестали выполняться: run() был переопределён, а вызов run_tests() забыли. Скрипт формально завершался успешно за долю секунды — просто потому, что не делал вообще ничего.
Практический чек перед тем, как считать перенос завершённым: открыть класс скрипта, найти все методы test_*, убедиться, что либо run() не переопределён (тогда всё запустится автоматически), либо внутри переопределённого run() явно стоит вызов self.run_tests(). Заодно проверяю, что каждый test_* действительно вызывает self.fail() или логирует через log_failure при найденной проблеме, а не просто возвращает значение — в Reports такая привычка проходила безнаказанно, в Scripts тихое return False без логирования просто не покажет администратору, что проверка не пройдена. Тот же принцип — не доверять тихому «успешному» завершению без явного лога — я закладываю и в аудит последнего входа в Active Directory: скрипт должен явно показать, что именно он проверил, а не просто отработать без ошибок.
Meta-класс и переменные: чего не было в Reports
У Custom Script есть вложенный класс Meta с параметрами, которых в Reports не было вовсе. name и description задают отображаемое имя и описание в интерфейсе — без них используется имя Python-класса. field_order определяет порядок полей формы, fieldsets группирует поля по разделам. commit_default управляет тем, отмечен ли чекбокс коммита по умолчанию (по умолчанию True), scheduling_enabled разрешает или запрещает запуск скрипта по расписанию, notifications_default задаёт политику уведомлений (always, on_failure, never), а job_timeout ограничивает максимальное время выполнения.
Это открывает то, чего физически не могли делать Reports: спросить у пользователя параметр перед запуском проверки. Например, вместо жёстко зашитого в код списка сайтов можно добавить ObjectVar с выбором конкретного сайта и гонять проверку адресного плана только по нему, а не по всей базе целиком каждый раз. Доступные типы переменных — StringVar, TextVar, IntegerVar, DecimalVar, BooleanVar, ChoiceVar, MultiChoiceVar, ObjectVar, MultiObjectVar, FileVar, IPAddressVar, IPAddressWithMaskVar, IPNetworkVar, DateVar, DateTimeVar. Для переноса старого отчёта это необязательный шаг, но именно он превращает механическую конвертацию в реальное улучшение: то, что раньше запускалось по всей базе и десять минут, можно ограничить одним сайтом или одним тегом.
Что дальше: deprecation Custom Scripts в 4.7
Здесь есть нюанс, о котором стоит знать, даже если вы только что закончили перенос Reports в Scripts. Начиная с NetBox v4.7 (релиз 2 сентября 2026 года) встроенная в ядро функциональность Custom Scripts сама объявлена устаревшей: документация формулирует это как «the custom scripts functionality built into core NetBox has been deprecated in favor of a dedicated plugin, and will be removed in NetBox v5.0». То есть та же история, что произошла с Reports в 4.0, ждёт и встроенные Scripts — только теперь заменой станет не другой встроенный механизм, а отдельный открытый плагин.
На практике это не значит, что нужно сейчас же останавливать перенос Reports в Scripts и ждать плагин. Документация прямо говорит, что встроенная реализация остаётся поддерживаемой на протяжении циклов 4.7 и 4.8, существующие скрипты продолжат работать как раньше, а сам переход на плагин задуман как в основном автоматический, без переписывания скриптов. Страница Reports тоже формулирует однозначно: конвертация отчёта в скрипт остаётся рекомендуемым первым шагом. Конкретное название плагина-замены я здесь не привожу — сверяйте с актуальной документацией. Мой практический совет: переносите Reports в Scripts сейчас, а переход на плагин делайте отдельным проектом до обновления на 5.0.
Кейс: перенос проверок адресного плана у «Найм Профи»
Условный клиент — рекрутинговая компания «Найм Профи», 13 рабочих мест. NetBox у них использовался для учёта сетевого оборудования и адресного плана трёх подсетей офиса, и на старой версии 3.7 были заведены два самописных Reports: один проверял, что у всех префиксов заполнено описание, второй — что у каждого устройства в DCIM указан серийный номер. Оба отчёта работали годами и запускались вручную раз в месяц перед сверкой инвентаризации.
После апгрейда до 4.x оба отчёта появились в интерфейсе уже как скрипты, история прошлых запусков сохранилась, и первые две недели всё работало на совместимом классе Report. Проблемы начались, когда администратор компании решил «довести миграцию до конца» и просто заменил импорт и родителя на Script. Проверка серийных номеров продолжила отрабатывать без ошибок, но в журнале вместо «нет серийного номера» стояли имена устройств — в коде был позиционный вызов log_failure(device, 'нет серийного номера') в старом порядке Report. Во втором скрипте, про описания префиксов, ещё во времена Reports был переопределён run(): из него вызывался только один тестовый метод, а два других, добавленных позже, не запускались никогда — это вскрылось только при переносе.
На перенос у меня ушло примерно четыре часа: поправил порядок аргументов в вызовах логирования, заменил ручной вызов одного теста на self.run_tests(), добавил Meta с понятным именем и описанием для обоих скриптов, и для проверки серийных номеров добавил ObjectVar с выбором конкретного сайта — раньше отчёт всегда гонял всю базу целиком, хотя админу чаще нужен был только один филиал. Заодно этот же скрипт завели в CI-пайплайн компании на self-hosted runners для GitHub Actions, чтобы проверка адресного плана запускалась не только вручную раз в месяц, а автоматически при каждом крупном изменении инфраструктуры в репозитории с конфигурацией. После переноса администратор компании получил не просто рабочую замену старым Reports, а более быстрый инструмент: проверка одного сайта вместо всей базы занимает несколько секунд вместо прежней почти минуты на полный прогон.
Частые ошибки при переносе
Самая распространённая ошибка — решить, что апгрейд уже всё перенёс, и не открыть код вообще. Формально всё запускается: записи сконвертированы, история заданий сохранена, старый код живёт на совместимом классе Report. Но этот класс — временный мост, а не решение: его удалят, и тогда отчёты перестанут загружаться разом. Вторая половина той же ошибки — сменить родителя на Script и не проверить позиционные вызовы логирования и незапущенные test_*. Это ответственность администратора, а не NetBox.
Вторая ошибка — оставить в скрипте комментарии и переменные с именем Report, из-за которых новый администратор через год не понимает, что перед ним на самом деле полноценный Script с возможностью параметров и расписания. Я всегда явно переименовываю класс и переписываю description в Meta, чтобы было видно: это не пережиток старой системы, а рабочий инструмент, который можно развивать дальше — добавлять переменные, расписание, уведомления.
Третья, более отложенная во времени ошибка — не заглядывать в release notes новых версий вообще. Пропустить deprecation Custom Scripts в 4.7 и узнать о нём только в момент обновления до 5.0, когда встроенный механизм уже уберут, а замена не будет подготовлена. Я держу в привычке смотреть changelog каждой мажорной версии NetBox, даже если апгрейд планируется не сразу — deprecation-предупреждения дают достаточно времени на спокойный перенос, если их читать вовремя, а не постфактум. Ту же привычку — не ждать, пока автоматика сломается сама, а проверять заранее по расписанию — я использую и в мониторинге SSL-сертификатов через PowerShell: дешевле один раз настроить регулярную проверку, чем потом разбирать аварию постфактум.
Частые вопросы
С какой версии NetBox Reports считаются устаревшими?
С версии 4.0 (релиз 6 мая 2024 года). Функциональность Reports объединена с Custom Scripts; при апгрейде записи об отчётах автоматически конвертируются в скрипты с сохранением истории, а старый код временно работает на совместимом классе Report.
Теряется ли история запусков отчётов при переходе на Scripts?
Нет. Документация NetBox гарантирует сохранение истории заданий (job history) при автоматической конвертации Reports в Scripts во время апгрейда до 4.0.
Почему после смены класса Report на Script логи стали бессмысленными?
В Report сигнатура была log_failure(obj, message), в Script — log_failure(message=None, obj=None). Совместимый класс Report переставлял аргументы сам; после смены родителя позиционные вызовы меняют сообщение и объект местами. Переходите на именованные аргументы, а log() замените на log_info().
Почему методы test_* перестали запускаться после переноса?
Методы test_* запускаются автоматически только если run() не переопределён. Если в скрипте есть собственный run() (что типично для перенесённых Reports), тестовые методы нужно явно вызвать через self.run_tests() внутри этого run().
Нужно ли сейчас переходить с Custom Scripts на плагин, раз они тоже объявлены устаревшими?
Не срочно. С версии 4.7 (2 сентября 2026 года) встроенные Custom Scripts объявлены устаревшими в пользу отдельного плагина, но ядро поддерживает их в циклах 4.7 и 4.8, удаление запланировано на v5.0. Переносите Reports в Scripts сейчас, а миграцию на плагин планируйте отдельно.
Чем Custom Script функционально лучше старого Report?
Script умеет запрашивать параметры у пользователя перед запуском через типизированные переменные (StringVar, ObjectVar и другие) и управлять записью изменений через флаг commit. Запуск по расписанию был и у Reports, так что главный выигрыш — параметры.
Источники
- NetBox Documentation — Reports (Converting Reports to Scripts) — Deprecation Reports с 4.0, автоконвертация записей при апгрейде с сохранением истории, смена импорта/базового класса, таблица сигнатур log_*(obj, message) → log_*(message, obj), замена log() на log_info(), pre_run()/post_run(). https://netboxlabs.com/docs/netbox/customization/reports/
- NetBox Documentation — Custom Scripts — Структура класса Script, Meta (name, description, field_order, fieldsets, commit_default, scheduling_enabled, notifications_default, job_timeout), run(self, data, commit), test_* и run_tests(), методы log_*, типы переменных, deprecation с 4.7 в пользу плагина. https://netboxlabs.com/docs/netbox/customization/custom-scripts/
- NetBox Release Notes — Version 4.0 — Дата релиза 6 мая 2024, удаление legacy reports, автоконвертация в custom scripts при апгрейде. https://netboxlabs.com/docs/netbox/release-notes/version-4.0/
- NetBox Release Notes — Version 4.7 — Дата релиза 2 сентября 2026, deprecation встроенных custom scripts в пользу отдельного плагина, удаление запланировано в v5.0 (issue #22935). https://netboxlabs.com/docs/netbox/release-notes/version-4.7/
- GitHub netbox-community/netbox — Discussion #17557 — Практический опыт миграции 3.6.9 → 4.0.11: изменение работы со SCRIPTS_ROOT, необходимость импорта скриптов через GUI/Data Source. https://github.com/netbox-community/netbox/discussions/17557
- NetBox Labs Blog — Getting Started With NetBox Custom Scripts — Пример структуры Script: базовый класс extras.scripts.Script, класс Meta, run(self, data, commit). https://netboxlabs.com/blog/getting-started-with-netbox-custom-scripts/



