Files
ipam_control/docs/changes/010-next-free-prefix/SUMMARY.md
T
ayurishchevandClaude Sonnet 5 cd09ef0805 Задачи 006-010: пользователи, исправление удаления, журнал отказов, групповые операции, автовыделение префиксов
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>
2026-09-26 13:25:33 +03:00

4.6 KiB
Raw Blame History

Итог: автовыделение следующего вложенного префикса (изменение 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. Код приложения не менялся.