When closing a Docker node, if container deletion fails, the error
is silently ignored. This can lead to stale containers remaining on
the system and causing 409 conflicts when reopening projects.
Changes:
- Distinguish between 404 (container already removed, normal) and
other DockerError (deletion failed, needs attention)
- Log warning when deletion fails with error details
- Add comment explaining stale containers will be cleaned up on
project open (via automatic 409 conflict resolution)
This improves observability without blocking project close operations.
The root cause of stale containers can now be diagnosed from logs.
Fixes#2708
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When a remote compute is unreachable, the controller now uses exponential
backoff for reconnection attempts: 5s, 10s, 20s, 40s, 80s, then caps at
300s (5 minutes). Previously it retried every 5 seconds indefinitely.
User-initiated operations (open project, start node) still trigger an
immediate connection attempt, so recovery is not delayed in practice.
Related: #2704
When opening a closed project with nodes on an offline remote compute,
open() would block for 120s trying to connect before eventually
failing. Now checks compute connectivity after loading the topology
file but before creating nodes, allowing immediate failure with a
clear error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously the disconnected compute check ran after open(), which would
block for 120s trying to connect to unreachable remote computes before
rejecting the deletion. Now reads the topology file directly to extract
compute IDs and checks connectivity before calling open(), enabling
immediate rejection of deletions involving offline computes.
Also removes the redundant post-open() check since the early check
covers both opened and closed project states.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously errors during close() and delete_on_computes() were silently
swallowed without any logging, making it difficult to diagnose failures
when remote computes are unreachable.
- close(): log warning instead of silent pass
- delete_on_computes(): wrap HTTP DELETE in try/except with warning log
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When deleting the AUTOIDLEPC project in autoidlepc(), if a remote compute
is disconnected, the deletion fails with ControllerForbiddenError due to
our compute connection status check. This causes:
- The project to remain in the controller's memory
- Subsequent autoidlepc calls to fail
- User must restart the server to recover
This fix adds exception handling to ensure the project is always removed
from the controller's memory, even if deletion fails.
Related to #2703
The initial fix used _project_created_on_compute to check for disconnected
computes before deletion, but this set gets reset during project.open(),
causing the check to fail.
Now uses self._computes which is loaded from the topology file and
persists through the open() call.
Related: #2703
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit addresses issue #2703 where deleting a project with nodes
on remote compute nodes would result in long waits with no feedback
if those computes were unreachable.
Changes:
1. Compute connection status updates on connection failure
- When a compute fails to connect, update connected=False and last_error
- Send compute.updated notification to UI so users can see status
- This allows Web UI to display real-time connection status
2. Project deletion checks compute status before attempting deletion
- Check all computes used by the project are connected
- If any compute is disconnected, immediately reject deletion
- Provide clear error message indicating which computes are offline
- This prevents long timeouts and gives users immediate feedback
Benefits:
- Immediate feedback instead of 120-second timeouts
- Clear error messages about which computes are disconnected
- Prevents orphaned resources on offline computes
- Improves user experience by avoiding silent waits
Related: #2703
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously only the "path" field was converted to a relative path for remote computes, causing issues with QEMU and VMware nodes that use different image path fields. Now all known image path fields are converted, ensuring consistent behavior across IOU, QEMU, Dynamips, and VMware node types.
When creating a node on a remote compute, the controller now sends
only the image filename instead of the absolute local path. The remote
compute will search for the image in its own configured images_directories.
If the image is not found, the compute returns ImageMissingError, which
triggers the controller's automatic image upload mechanism.
This fixes issue #2676 where remote computes reject paths from the
controller due to mismatched directory prefixes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When accessing /static/web-ui without trailing slash, the request would
fail with "RuntimeError: File at path ... is not a file" because:
1. The route /static/web-ui/{file_path:path} doesn't match paths without
trailing slash (Starlette's path regex requires the /)
2. The request falls through to StaticFiles mount, which tries to serve
the directory as a file
This fix:
- Sets html=True on StaticFiles mount to automatically redirect directory
URLs to trailing slash versions
- Adds os.path.isdir() check to handle empty file_path gracefully
Fixes#2680
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fixes#1658
Add validation in the update_template method to check if a template
with the same name already exists before updating. This prevents
users from creating duplicate template names by editing existing
templates.
The check excludes the current template being edited to allow
updating other properties without changing the name.
When updating a compute without providing a password field,
compute_update.password is None and calling .get_secret_value()
on it causes a 500 Internal Server Error. Only set the password
in update_values when a password is actually provided.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a hostname validation fails, the error message now includes
the allowed character set to help users provide valid names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add documentation explaining the common issue where WebSocket console connections to remote compute nodes fail due to credential mismatch. The guide describes the error symptoms, root cause (Controller forwarding its own credentials to Compute), and solution (ensuring matching compute_username and compute_password in Compute's configuration).
This section was misleading - the actual root cause is host=0.0.0.0
causing controller to register as 127.0.0.1, not hostname resolution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add details about the "No common subnet" error when Controller's host
is set to 0.0.0.0, and how to verify via /v3/version endpoint.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add documentation for the "No common subnet" error when the
controller's hostname in /etc/hosts resolves to an unreachable
or stale IP address.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>