006 Пользователи: API /users (CRUD, смена своего пароля), раздел UI «Пользователи»,
события журнала user.*, защита от отключения/удаления себя и последнего админа.
007 Исправление удаления организации: VRF удаляются явным DELETE до организации
(без relationship() порядок DELETE не гарантирован → ложный 409).
008 Журнал фиксирует отказы в удалении (<entity>.delete_blocked) со списком
мешающих объектов в «Данных»: организация, VRF, тип устройства, префикс, пользователь.
009 Выбор строк чекбоксами и групповые операции в UI (удаление, смена типа устройств,
статус префиксов и адресов, доступ пользователей); цикл запросов из UI, итог и список отказов.
010 Автовыделение следующего вложенного префикса: POST/GET /prefixes/{id}/subnets/next,
первый свободный выровненный блок; пункт «Добавить вложенный (авто)» в меню префикса.
Тесты: 14 (добавлены сценарии для 006, 007/008, 010); исправлена нестабильность
тестов журнала (IPv6-группы с ведущими нулями нормализуются PostgreSQL).
Документация: README.md, docs/changes/006-010 (планы и итоги).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4.6 KiB
4.6 KiB
Итог: автовыделение следующего вложенного префикса (изменение 010)
Что сделано
- Алгоритм
next_free_subnet()(app/services.py): первый свободный блок заданного размера внутри родителя, выровненный по границе блока; занятое — все префиксы внутри родителя в том же VRF (любой вложенности) и адреса, записанные на самом родителе. Перескок за конец занятого диапазона, без перебора подсетей (работает для IPv4 и IPv6). Примеры:.0/30занят →.4/30; после.0/.4/.8блок/29→.16/29(выравнивание);/25при занятой нижней половине →.128/25. - API (
app/api/v1/prefixes.py,app/schemas.py):POST /prefixes/{id}/subnets/next(admin;length,description,status,is_pool,note) создаёт вложенный префикс в VRF и организации родителя, 201;GET /prefixes/{id}/subnets/next?length=— предпросмотр без создания. Размер вне/родитель+1 … /32|/128→ 422; нет свободного блока → 409 «В префиксе … нет свободного блока /N». Родитель блокируетсяFOR UPDATE(параллельные запросы не получают один блок); журнал —prefix.createdсallocated_from. - UI (
web/app.js): пункт «Добавить вложенный (авто)» в меню «⋯» строки префикса (у листовых — вместе с прежними, у родителей — новое меню из одного пункта; только admin). Окно: «Размер» (по умолчанию — как у последнего дочернего, иначе /30 для IPv4 и /64 для IPv6), живая строка «Будет создан: 100.70.0.4/30», описание, статус, примечание, флажок «Пул». Если места нет — предупреждение и заблокированная кнопка. После создания родитель раскрывается. - БД и миграции не менялись. Документация:
README.md, план и итог.
Проверка
test_allocate_next_subnet(14 passed всего): предпросмотр = создание,.4/30,.8/30, выравнивание/29, 422 на неверный размер,/25, затем 409, проверка IPv6 в чистой функции.- Сквозная проверка в headless Chromium: родитель + ручной /30 → три вызова из меню подряд дали
.4,.8,.12; смена размера на /29 → предпросмотр.16/29; пункт есть у листа; запись в журнале сallocated_from. Тестовые данные удалены.
Ограничения
- Блок всегда первый по возрастанию адреса (без поиска «наилучшего» по фрагментации). Освободившийся раньше блок будет выдан повторно.
- За раз создаётся один префикс; массовое выделение (N подряд) можно добавить отдельно.
- Адреса, привязанные к самому родителю, считаются занятыми: блок с ними не выдаётся.
Попутно: нестабильные тесты журнала
Тесты tests/test_journal.py изредка падали (assert 0 >= 1, IndexError), в изменениях 007–009 это отмечалось как «разовый сбой без выявленной причины». Причина найдена: тестовый IPv6-префикс собирался из
случайных hex-групп с ведущими нулями (fd00:0e3a:…), а PostgreSQL хранит CIDR в нормализованном виде (fd00:e3a:…), поэтому поиск по журналу не находил запись (~1 из 8 запусков на тест).
Исправлено в тестах (группы без ведущих нулей); 6 полных прогонов подряд — 14 passed. Код приложения не менялся.