feat: Volume/FIP Attach-Detach — Bidirectional Operations (#61)#61
Merged
Conversation
Add bidirectional attach/detach/associate/disassociate operations for cloud infrastructure operators. Includes safety guards, audit logging infrastructure, and enhanced UI components. Key changes: - Volume: a(attach), x(detach), D(delete), F(force detach), R(state reset) - FloatingIP: a(associate), x(disassociate), D(delete) - Server detail: A(attach vol), x(detach vol), f(associate FIP) - SelectPopup inline search (/ key with mode-aware navigation) - ConfirmDialog detail_lines for rich confirmation context - CrossTenantGuard: all_tenants CUD block + break-glass toggle - TransitionGuard: attaching/detaching state key disable - AuditLogger infrastructure (JSON Lines + rotation) - Port model + CinderPort::force_detach + NeutronPort::list_ports - ActionKind::Attach/Detach RBAC with preflight checks - Keymap migration hints (d→D transition) Tests: 866 → 1017 (+151) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…achVolume
- Move attach_volume/detach_volume from CinderPort stubs to NovaPort
(Nova os-volume_attachments API is the correct endpoint)
- Add server_id field to DetachVolume/ForceDetachVolume Action/PendingAction
(needed for Nova DELETE /servers/{id}/os-volume_attachments/{vol_id})
- Implement NovaHttpAdapter::attach_volume (POST) and detach_volume (DELETE)
- Add NovaPort mock implementations
- Fix all test pattern matches to include server_id
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add volumes_attached field to Server model (os-extended-volumes API) - Add AttachedVolume model with id and delete_on_termination - Display Volumes section in server detail with name, size, status, device - Resolve volume details from cached_volumes for rich display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Resolve server_id to "server-name (uuid-prefix)" using cached_servers. Operators can now identify attached servers without memorizing UUIDs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Displays volume count per server in the list view for quick visibility. Shows "-" when no volumes attached, count number otherwise. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Display Server Name and Server ID as separate full columns instead of truncated "name (uuid-prefix)" format. Operators need both for reference. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously 404 errors discarded the response body, showing only "Not found: " with empty fields. Now the body is preserved in the id field so operators see the actual error (e.g. Neutron's "ExternalGatewayForFloatingIPNotFound" message). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Parse NeutronError, badRequest, itemNotFound, etc. to extract the "message" field instead of dumping raw JSON into toast messages. Operators now see actionable error text instead of truncated JSON. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Show associated floating IPs with address mapping (FIP → fixed IP), ID, and status. Matches FIPs from cached data by comparing floating IP addresses in server.addresses with cached_floating_ips. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Admin UX principle: interconnected resources should show connection points everywhere. - Volume list "Attached To": show server name + device instead of UUID - FIP list: replace "Network ID" column with "Associated Server" showing resolved server name via port_id → device_id → server name lookup Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
ShowToast for 'd' key hint was sent via action_tx (worker channel) which ignores it. Changed to return Some(Action::ShowToast) from handle_key so App::dispatch_action processes it directly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update local FIP status/port_id immediately on event receipt for instant visual feedback in the list view, before async FetchFloatingIps completes. Move re-associate hint to generate_toast for proper display. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
App-level search mode was setting input_mode to Search but had no key handling beyond Esc, causing the UI to freeze. Disabled it so '/' is now only handled by SelectPopup when open. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… detach P1 fixes from Codex review: - PortsLoaded: track pending_ports_server_id and reject mismatched responses to prevent associating FIP with wrong server's ports (both ServerModule and FloatingIpModule) - Server detail detach: apply same boot volume safeguard as VolumeModule (non-admin blocked, admin requires TypeToConfirm with warning) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes (18 files, +3313 lines)
Test plan
🤖 Generated with Claude Code