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

29 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Итог: автовыделение следующего вложенного префикса (изменение 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. Код приложения не менялся.