Commit Graph
12 Commits
Author SHA1 Message Date
ayurishchevandClaude Sonnet 5.5 aff8fe38b5 Scan floating IPs in the background, page by page, so thousands of addresses work
The "Scan Floating IP" button failed with a client timeout: the project now
holds ~6.4k floating IPs and the scan listed them all in one unpaginated,
timeout-less Neutron request on the HTTP request context.

openstack: ListFreeFloatingIPs reads marker-based pages (fields= keeps them
small) with per-page retry/backoff on transport errors, 5xx and 429, and every
request now has a timeout (also ends hangs inside the orchestrator tick).

orchestrator: the scan is a single-flight background job on the process
context with progress (clearing/listing/enqueuing/done/error), dry_run, full
discovery before anything is enqueued, then SubmitIPs in chunks of 500 in
ascending IP order; a failed read leaves the queue untouched. The auto-cycle
gets a "scanning" phase that polls the job, so the control loop and
autoCycleMu are never held across OpenStack/DB work; it recovers after a
restart and waits for (instead of adopting) a scan started by someone else.

db: migration 0009 (indexes), paged ListIPsPage/ListRegistryPage, GROUP BY
counters, EXISTS completion check, set-based ClearAllIPs.

API: POST /admin/ips/scan -> 202 (dry_run, wait), GET /admin/ips/scan, paging
and filters on /admin/ips and /admin/registry (bare arrays without limit),
results_by_overall in /admin/status.

dashboard: scan progress panel and dry-run button, paginated /ips and
/registry with server-side filters, Overview on counters and capped lists
with progress/ETA, "select all N by filter", hx-params fix for per-row
buttons, real counts in confirmations.

Also: docs (API, USAGE, DASHBOARD, README), plan and review under
docs/changes/, bin/ rebuilt with new SHA256SUMS.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-01 19:31:11 +03:00
ayurishchevandClaude Sonnet 5 582b44f314 Add Floating IP scanning and a durable address registry with configurable history depth
Adds POST /api/v1/admin/ips/scan (plus an optional periodic ticker) to
discover free Floating IPs in the OpenStack project and feed them straight
into the check queue. More importantly, decouples check/event history from
ip_queue's lifecycle: a new ip_registry table (migration 0007) gives every
address ever submitted a durable identity, so deleting it from the queue no
longer destroys its history — it's still reachable via the new
GET /api/v1/admin/registry[/{ip}] endpoints and the dashboard's /registry
pages, with retention depth configurable in check cycles per address
(history_retention_cycles, 0 = unlimited).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 09:52:01 +03:00
ayurishchevandClaude Sonnet 5 78b20fa5be Remove IPs page auto-refresh; clear checkboxes after bulk recheck
The 5s auto-refresh (ec44d54) and the hx-sync fix on top of it (5a53705)
didn't resolve the issues seen in manual testing. Rather than keep
debugging htmx's polling/preserve/sync interaction, drop auto-refresh
entirely: handleIPsFragment, GET /ips/fragment, and the poll
attributes/PollSeconds plumbing are all removed. The table now only
updates when a button action re-renders it, as it did before auto-refresh
was added — the bulk-recheck feature itself (handleIPsRecheckSelected,
POST /ips/recheck, "Перепроверить выбранные") is untouched.

Also drops hx-preserve/id from the row checkboxes: it existed solely to
survive the auto-poll wiping a selection mid-task, so it has no purpose
left, and it was actively wrong for one case — after a successful
"Перепроверить выбранные", it kept the just-submitted addresses checked
instead of clearing them. Since the checkbox's checked state was never
server-rendered to begin with, removing hx-preserve alone makes every
table swap (including the recheck button's own) render fresh, unchecked
boxes, which is exactly the desired "selection clears once the action has
been applied" behavior.

Left hx-sync="#ips-table-wrap:queue last" on the action buttons/form —
still cheap protection against a double-click race between two real user
actions, independent of the now-removed polling.

Rebuilt bin/admin-dashboard and bin/SHA256SUMS per docs/SETUP.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 19:29:26 +03:00
ayurishchevandClaude Sonnet 5 5a53705217 Fix IPs page race between auto-refresh polling and action buttons
The 5s auto-poll (hx-trigger="every Ns" on #ips-table-wrap) and every
button/form that also swaps #ips-table-wrap (bulk recheck/delete/clear,
per-row recheck/cancel/delete, the add-address form) each fired
independent, uncoordinated htmx requests against the same target. With no
hx-sync, whichever response landed last won — including a poll's
in-flight GET landing *after* a slower mutation's own response and
silently reverting the just-applied change with stale data. This matched
every symptom reported: buttons needing several clicks before they
"took", "Перепроверить выбранные" appearing to do nothing with many rows
selected (more DB writes -> wider race window for a poll to land after
and clobber it), the page "blinking" back to a stale queued state a few
seconds after a bulk recheck actually succeeded, and auto-refresh working
"every other time".

Every element that targets #ips-table-wrap now shares
hx-sync="#ips-table-wrap:queue last", so at most one request affecting it
is ever in flight: a trigger that fires while another is pending gets
queued (never aborted mid-write) and only the most recent queued trigger
actually runs once the current one finishes, guaranteeing responses are
always applied in the order they actually resolve.

Rebuilt bin/admin-dashboard (only internal/dashboard changed) and
bin/SHA256SUMS per docs/SETUP.md's documented build recipe.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 19:10:05 +03:00
ayurishchevandClaude Sonnet 5 ec44d54ac1 Add bulk recheck and auto-refresh to the IPs dashboard page
"Перепроверить выбранные" joins the existing "Удалить выбранные" / "Очистить
всё" bulk actions, using the checked-row selection the same way delete
already does — no control-api changes needed, since forcing a recheck of a
batch of addresses (new, finished, or already-queued, skipping anything
mid-check) is exactly what POST /api/v1/admin/ips (db.SubmitIPs) already
does, and the dashboard's own SubmitIPs client method already backs both
the top add/recheck form and the single-row recheck button.

The page also now auto-refreshes every 5s (handleIPsFragment + GET
/ips/fragment), mirroring the overview page's existing hx-trigger="every
Ns" polling and reusing the same config-driven interval
(Cfg.OverviewPollIntervalS) rather than adding a duplicate knob. Since the
table now polls itself, each row's selection checkbox gets a stable id
plus hx-preserve so a checked box survives the refresh (its own DOM node
is kept) while the rest of the row still updates live.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 18:47:11 +03:00
ayurishchevandClaude Sonnet 5 93c79b63ea Skip the check cycle for a Floating IP already occupied by another port
The cloud is live: the address list submitted as "free" (bootstrap config
or POST /api/v1/admin/ips) can drift by the time the orchestrator claims
it, or an operator can queue an already-occupied address by mistake.
Neutron's floating-IP association is a blind "last write wins" PUT with
no conflict error to catch, so associateFIP now checks the FIP's PortID
(already fetched via GetFloatingIPByAddress) before associating, guarded
against the false-positive of the FIP already belonging to this same
validator's own port.

A match routes the address straight to a new terminal ip_queue.state
("occupied", distinct from failed/fail) via db.MarkFIPOccupied — no
retries, since Neutron won't free it on its own and requeuing would let
it be reclaimed again next tick, starving the rest of the queue — plus a
dedicated fip_occupied audit event. Resubmitting the address later (once
the conflict is resolved) resets it to queued via the existing
POST /api/v1/admin/ips resubmit path (CancelIP/ListExpiredLeases updated
to treat occupied as terminal too). admin-dashboard gets its own "занят"
badge, distinct from fail/partial/cancelled.

Rebuilt bin/{control-api,admin-dashboard,prober,validator-agent} and
bin/SHA256SUMS per docs/SETUP.md's documented build recipe, since
control-api and admin-dashboard source changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NeVbMVEiE7XQAkBd7HQgj6
2026-09-13 23:54:35 +03:00
ayurishchev 7a93594e69 Minor UI fixes 2026-08-26 22:19:42 +03:00
ayurishchev f22ad569b6 added FIP Cooldown before start 2026-08-24 10:29:08 +03:00
ayurishchev f8336740ad feature: handle delete operation for IPs 2026-08-23 22:24:55 +03:00
ayurishchev 4f597505cc UI fix 2026-08-23 21:58:19 +03:00
ayurishchev ee2a29cb36 use bootstrap 5 for UI, compact UI 2026-08-23 21:15:31 +03:00
ayurishchev 37910e410b admin control features and admin dashboard 2026-08-23 20:39:22 +03:00