- Register packet_analysis_skills as a LangChain tool for LLM
- LLM can query protocol field definitions before calling packet_analysis
- Follows the same pattern as DeviceSkillsTool and InjectionSkillsTool
- Delete packet_capture_tools.py (analyze_packets with packet_number)
- PacketAnalysisTool is more flexible and can do everything the old tool could
- Update tool registration to use only PacketAnalysisTool
- Cleaner, more unified packet analysis interface
- Add PacketAnalysisTool that accepts user-provided tshark arguments
- LLM constructs tshark commands based on protocol knowledge from skills
- Add PACKET_ANALYSIS_REGISTRY for protocol definitions
- Add load_packet_analysis_protocols() to SkillsLoader
- Add get_packet_analysis_protocol() and list functions to registry
- Register PacketAnalysisTool in teaching and lab automation modes
- Update SkillsManager to reload packet analysis protocols
Related: GNS3-Skills commit 7bc45d2
Close GitHub issues and document as roadmaps instead:
- #2731: user preferences API
- #2732: server settings REST API
- #2733: injection fault tracking
- packet analysis: protocol-oriented analysis architecture
- Remove 5s thread.join() timeout so git clone/pull is not truncated
- Remove _init_complete flag, reset _init_in_progress on failure instead
- Let /reload/skills API retry initialization after network failure
- Raise GIT_HTTP_LOW_SPEED_LIMIT from 1 KB/s to 10 KB/s
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add missing dependencies for the external skills repository feature:
- PyYAML>=6.0.0: for loading YAML skill files
- GitPython>=3.1.0: for Git operations (clone/pull) on skills repo
These dependencies are required by the SkillsManager and SkillsLoader
classes introduced in commit e68cc17e.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
## Summary
Add a complete fault injection system for GNS3 Copilot, migrate all
skills from local Python files to an external Git repository with
hot reload support, and restructure Copilot API under /copilot/.
## Key Changes
### Fault Injection
- New troubleshooting_injection mode with InjectionSkillsTool
- 368 fault scenarios across 39 protocol categories
- Context-based filtering (LLM must pass topology protocols)
### External Skills Repository
- SkillsManager: Git clone/pull, version tracking, smart updates
- SkillsLoader: YAML skills + Markdown prompts from external repo
- Hot reload via POST /copilot/reload/skills
- Configurable via gns3_server.conf
### Architecture
- API unified under /copilot/ prefix
- SkillsManager moved from Controller to agent module
- Lazy initialization with startup background preload
- Per-command Git timeout, smart update checks
- Forbidden commands hot-reloadable from external repo
- 32 INFO logs downgraded to DEBUG
DeepSeek models (deepseek-v4-flash/pro) enable thinking mode by default,
which returns reasoning_content that must be passed back to the API in
subsequent requests. This causes 400 errors in multi-turn conversations
when the reasoning_content is not properly handled.
This commit disables thinking mode by passing extra_body={"thinking": {"type": "disabled"}}
as an explicit parameter to DeepSeek models, preventing the reasoning_content
field from being generated.
Modified:
- create_base_model(): Add extra_body parameter with thinking mode disabled
- create_title_model(): Add extra_body parameter with thinking mode disabled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When importing a project, the round-robin logic would attempt to distribute
nodes across all configured compute resources, including offline ones. This
caused import failures when any remote compute was unreachable.
This fix filters the compute list to only include connected computes before
round-robin distribution. If no remote computes are connected, all nodes
are assigned to the local compute.
This matches the approach used in project._get_disconnected_computes() and
prevents the issue where importing a project fails with:
"Cannot connect to compute 'X' with request POST /projects"
Fixes issue introduced in commit 90e3a8d6 (2017) which added round-robin
load balancing without considering offline compute nodes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix F821 undefined name 'status' error by importing the status
module from fastapi. This resolves build errors when using
status.HTTP_403_FORBIDDEN and status.HTTP_404_NOT_FOUND.
Add exception handling in stop_wrap_console to gracefully handle
ConnectionResetError, BrokenPipeError, and OSError when waiting
for console writer to close.
This prevents 500 errors when stopping QEMU nodes if the console
connection is reset before the writer finishes closing.
Fixes race condition where QEMU process exits and closes connections
before the console writer cleanup completes.
Remove MD5 checksum calculation from the node files API since
disk image files are dynamic and change frequently. MD5 calculation
was also causing significant performance overhead.
Changes:
- Remove md5sum field from NodeFile schema
- Remove MD5 calculation from list_node_files method
- Improve error handling for timestamp conversion
- Simplify code by removing lambda functions
Performance improvement:
- Response time reduced from ~0.5-1s to ~0.017s (30-60x faster)
- Especially beneficial for large files and multiple files
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add NodeFile to the schemas __init__.py exports to fix
import error when starting the server.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Enhance the node files API to include comprehensive file metadata:
- File size in bytes
- File creation time (ISO 8601 format)
- File modification time (ISO 8601 format)
- File extension
Create new NodeFile schema to support these additional fields
while keeping the existing ProjectFile schema for backward compatibility.
This provides users with better information to manage and identify
files in the Web UI.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implement issue #2719 - Add API endpoint to list project files
- Add GET /v3/projects/{project_id}/nodes/{node_id}/files endpoint
- Add list_node_files() method to Project class
- Add security checks to prevent path traversal
- Filter out .ghost temporary files
- Return file paths with MD5 checksums
- Require Node.Audit privilege
This allows users to discover dynamically created files
such as QEMU disk images created via the disk image API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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>
The CLI entry point was renamed from 'wireshark' to 'gns3server-web-wireshark-setup'
to avoid conflicts with the system wireshark package.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The wireshark CLI entry point creates /usr/bin/wireshark which conflicts
with the system wireshark package on Arch Linux (owned by wireshark-qt),
causing package installation to fail.
Rename to gns3-wireshark to follow the same naming convention as other
GNS3 CLI tools (gns3server, gns3vmnet).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add verify=False to requests.get() when capture_url uses HTTPS protocol,
to skip SSL certificate validation. This allows PacketCaptureTool to
work with GNS3 servers using self-signed certificates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add -k flag to curl command when capture_stream_url uses HTTPS protocol,
to skip SSL certificate validation. This allows Web Wireshark to work
with GNS3 servers using self-signed certificates.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Document API version negotiation mechanism (1.44 with fallback to 1.40)
- Add tested configurations table for Docker 20.10 and 29.3+
- Document container IP retrieval dual-strategy approach
- Explain KeyError bug fix for missing NetworkSettings.Networks field
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Change initial API version from 1.40 to 1.44 to support Docker 29.3+ (API 1.54)
- Add automatic fallback to API 1.40 for older Docker versions (20.10, API 1.41)
- Fixes "client version 1.40 is too old. Minimum supported API version is 1.44" error
- Ensures compatibility across Docker versions 20.10 (API 1.41) to 29.3+ (API 1.54+)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add `get_container_ip` method to WebWiresharkManager for retrieving container IP addresses in wireshark network
- Method uses Docker API as primary approach with container command execution as fallback
- Refactor web_wireshark_websocket endpoint to use new method instead of direct Docker queries
- Improve error handling and logging for container IP retrieval failures
The minimum Docker API version was reduced from 1.44 to 1.40 to support older Docker installations that do not provide API version 1.44, ensuring the web Wireshark agent can connect to a wider range of Docker environments.
Support specifying custom GitHub repository URL and branch name
when syncing WebUI with gns3server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Document unified error response format across all GNS3 API endpoints,
including HTTP status codes, error types, and client-side error handling
patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace CDN-hosted swagger-ui-dist@3.30.0 with local static files
from gns3server/static/ to address CVE-2018-25031 vulnerability.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove deprecated --build-optimizer flag
- Update copy path from dist/ to dist/browser/ for new Angular build output
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(deps): upgrade pytest to 9.0.3 to fix CVE-2025-71176
CVE-2025-71176: pytest 9.0.2 and earlier versions have a local
security vulnerability due to predictable temporary directory naming.
- pytest: 8.4.2 → 9.0.3
- Python 3.10+ is now required
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(deps): upgrade python-multipart to 0.0.26 to fix CVE-2026-40347
CVE-2026-40347: python-multipart < 0.0.26 has a denial of
service vulnerability when parsing multipart data.
- python-multipart: 0.0.22 → 0.0.26
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(deps): upgrade swagger-ui to 4.1.3 to fix CVE-2018-25031
CVE-2018-25031: swagger-ui < 4.1.3 has a spoofing vulnerability
where remote attackers can display remote OpenAPI definitions
via crafted URLs.
- swagger-ui: 3.30.0 → 4.1.3
- Updated swagger-ui-bundle.js and swagger-ui.css
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(api): change FastAPI version from "v3" to "3.0.0" for Swagger UI 4.1.3 compatibility
Swagger UI 4.x enforces stricter version format validation.
The version "v3" is not accepted by the new validator.
Changed from:
- version="v3"
To:
- version="3.0.0"
This affects both controller and compute API definitions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(deps): upgrade swagger-ui to 5.32.4
Fixes "Unable to render this definition" error when loading OpenAPI 3.0
docs. Swagger UI 3.x had incomplete OpenAPI 3.0 support.
- swagger-ui: 3.19.1 → 5.32.4 (latest)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add implementation plan for script-driven integration
Add comprehensive implementation plan for Web Wireshark integration using script-driven approach. The plan outlines:
- Background and motivation for script-based Web Wireshark integration
- Core workflow from API request to WebSocket proxy connection
- Management script architecture with WebWiresharkManager class
- Docker container configuration and resource management
- Performance analysis and optimization recommendations
- Network setup and management procedures
Key features include:
- JWT token extraction from Authorization header
- Automatic GNS3 server URL detection
- Container lifecycle management per project
- Xpra session isolation per link
- WebSocket proxy integration through gns3server
- Resource monitoring and scaling guidelines
The implementation enables users to start Web Wireshark sessions via POST requests with `wireshark: true` parameter, providing a unified web-based packet capture interface.
* feat(web-wireshark): implement script-driven Web Wireshark integration
Add complete Web Wireshark container integration with script-driven architecture:
- Create manage_wireshark.py script for Docker container management
- Add LinkCapture schema with wireshark boolean field
- Update Link class with wireshark and jwt_token parameters
- Implement WebSocket proxy endpoint for xpra HTML5 client
- Add cleanup logic in Project class for container lifecycle
Key features:
- Script-driven container and xpra session management
- JWT token extraction from Authorization header
- GNS3 URL auto-detection with Controller/Config fallback
- WebSocket proxy for unified access through gns3server
- Proper cleanup on project close/delete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): use aiohttp instead of docker SDK
Replace docker-py SDK with direct Docker HTTP API calls using aiohttp,
following GNS3's existing architecture pattern in gns3server/compute/docker/.
Changes:
- Create DockerHTTPClient class using aiohttp + Unix socket
- Implement all Docker operations as async methods
- Remove dependency on docker Python SDK
- Use Docker API v1.44 via /var/run/docker.sock
Benefits:
- No additional dependencies required
- Consistent with GNS3's async architecture
- Better integration with existing codebase
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): add dynamic Docker API version detection
Implement dynamic Docker API version detection following GNS3's pattern
in gns3server/compute/docker/__init__.py.
Changes:
- Add DOCKER_MINIMUM_API_VERSION and DOCKER_PREFERRED_API_VERSION constants
- Remove hardcoded "v1.44" prefix (now using "1.44" format)
- Add _check_connection() method to detect Docker daemon version
- Dynamically select API version based on daemon capabilities
- Add proper error handling for version mismatches
Behavior:
- Initialize with minimum API version (1.40)
- On first connection, detect Docker daemon API version
- Use preferred API version (1.44) if supported
- Fall back to daemon's minimum API version if needed
- Raise error if daemon version is too old
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): add optional --verbose logging parameter
Remove hardcoded logging.basicConfig() and add --verbose parameter
to control log output, following GNS3's logging pattern.
Changes:
- Remove logging.basicConfig(level=logging.INFO) from module level
- Add --verbose/-v command line parameter
- Configure logging only when --verbose is specified
- Use structured log format with timestamp when verbose
Behavior:
- When called by GNS3: uses GNS3's logging configuration (default)
- When run standalone: no output unless --verbose is specified
- With --verbose: shows detailed logs with timestamps
This prevents the script from interfering with GNS3's logging
configuration while still allowing debug output when needed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): fix code quality issues from static analysis
Fix issues identified by flake8 and pylint static analysis:
Import and formatting fixes:
- Remove unused 'time' import
- Fix import order (stdlib before third-party)
- Remove unnecessary f-strings without placeholders
- Split long line to comply with flake8 (max line length: 127)
Code structure improvements:
- Remove unnecessary 'else' after 'return'
- Add 'from e' to exception re-raising for better tracebacks
Code quality metrics:
- pylint score: 8.11/10 → 9.97/10 (+1.86)
- flake8: 0 errors (max line length: 127, per CI/CD standard)
- All critical issues resolved
Note: R0914 (too-many-locals) warning is informational only,
code remains clear and maintainable.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): export LinkCapture schema in schemas module
Add LinkCapture to the schemas module exports in __init__.py to fix
the AttributeError when starting the GNS3 server.
Error was:
AttributeError: module 'gns3server.schemas' has no attribute 'LinkCapture'
This was caused by adding the LinkCapture class to controller/links.py
but forgetting to export it in the schemas __init__.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add --image parameter for custom Docker images
Add optional --image parameter to allow using custom Docker images
for testing, instead of requiring gns3/web-wireshark:latest.
Changes:
- Add --image parameter to start command (default: gns3/web-wireshark:latest)
- Update get_or_create_container() to accept image parameter
- Update start_wireshark_session() to accept and pass image parameter
- Update TEST.md with examples of using custom images
Usage:
# Using default image
python3 manage_wireshark.py start --project-id x --link-id y --jwt-token z
# Using custom image (for testing)
python3 manage_wireshark.py start --project-id x --link-id y --jwt-token z --image ubuntu:latest
This makes it easier to test the script without having the official
gns3/web-wireshark image available.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add configurable resource limits and increase session capacity
Add configurable resource parameters and increase session support from 10 to 100.
Resource parameters:
- --memory: Memory limit (default: 2g)
- --memory-swap: Memory swap limit (default: same as memory)
- --cpus: CPU cores (default: 1.0)
- --pids-limit: Process limit (default: 1000)
Other improvements:
- Fix CPU quota calculation: 1000000 microseconds = 1.0 CPU core
(was incorrectly 100000 = 0.1 CPU core)
- Add health check: xpra list command
- Add log configuration: json-file, max-size=10m, max-file=3
- Increase session capacity: 10 → 100 concurrent sessions
- Port range: 12300-12399 (was 12300-12309)
- Display range: :100-:199 (was :100-:109)
This matches the docker run command parameters and provides
better resource management and monitoring capabilities.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): update UDPLink.start_capture() to accept new parameters
Update UDPLink.start_capture() to accept the new wireshark and jwt_token
parameters and pass them to the parent Link class.
This fixes the TypeError when starting capture on UDP links:
TypeError: UDPLink.start_capture() got an unexpected keyword argument 'wireshark'
The UDPLink class overrides start_capture() but didn't include the new
parameters added for Web Wireshark support.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs: add project memory infrastructure and JWT token flow documentation
- Add memory skill for recording project knowledge
- Document JWT token flow in Web Wireshark integration
- Update .gitignore to track skills and memory directories
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): fix Docker API URL format and use docker exec CLI
- Add "v" prefix to Docker API URL (http://docker/v{version}/...)
- Remove unused exec_create/exec_start API methods
- Fix Healthcheck.Test format to ["CMD-SHELL", "command"]
- Use docker exec CLI instead of Docker API for command execution
- This aligns with GNS3 docker_vm pattern
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): improve xpra session management and error handling
- Check and clean up existing sessions before starting new xpra session
- Add verification that xpra session started successfully
- Use docker exec CLI consistently instead of Docker API
- Improve error logging and diagnostics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add timeout handling and container health checks
- Add REQUEST_TIMEOUT constant for Docker HTTP API requests
- Add asyncio.timeout wrapper for Docker API calls to prevent hanging
- Add _is_container_healthy() to check container responsiveness
- Add _exec_in_container() helper with timeout support
- Improve unhealthy container handling with force remove
- Add detailed logging for container health state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): split monolithic file into modules
Split manage_wireshark.py into:
- docker_client.py: Docker HTTP API client
- manager.py: WebWiresharkManager with session management
- manage_wireshark.py: CLI entry point
This improves code organization and maintainability.
Keep all timeout handling and health check logic.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): correct NanoCpus calculation to use nanoseconds
NanoCpus in Docker API requires nanoseconds (1 CPU = 1000000000),
not the previous incorrect multiplier of 100000.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): fix xpra command quoting and session verification
- Add quotes around --xvfb parameter value to preserve spaces
- Fix session verification to check display number instead of session name
(xpra list shows "LIVE session at :185" not session name)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): run wireshark in background with &
Wireshark with curl pipeline runs continuously, so it must run
in background to avoid blocking. Also reduced timeout since we
don't wait for completion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add deterministic hash for display/port allocation
Use MD5-based hash instead of Python's hash() which is randomized
across process restarts. This ensures display and port numbers are
stable when the GNS3 server restarts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: extract link_id_to_port to shared utils module
Move deterministic hash functions to gns3server/utils/port_allocator.py
to avoid code duplication and ensure consistent algorithm across
manager.py and links.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(links): move import to top of file
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web-wireshark): use correct Config access pattern like gns3-copilot
The Server config is an object with .protocol.value, .host, .port
attributes, not a dict. Fixes URL detection failing and falling back
to 127.0.0.1:3080 which doesn't work from inside containers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add UUID validation utility and use in manage_wireshark
Create gns3server/utils/uuid_validator.py with validate_uuid function
to validate UUID format and catch typos early with clear error messages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use argparse.ArgumentTypeError for proper error message display
Previously ValueError was used which only showed 'invalid validate_uuid value'.
Now shows the full helpful message about expected format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add --dpi=96 to xpra start parameters
Set standard DPI for better display scaling in web Wireshark.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: update TEST.md with correct project-id format
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web-wireshark): hide xpra shutdown menu via XPRA_CLIENT_CAN_SHUTDOWN
Prevents users from accidentally shutting down the xpra server
through the HTML5 client menu.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(memory): add xpra-html5-client configuration reference
Document xpra HTML5 client configuration including:
- URL parameters for toolbar menu control
- default-settings.txt parameters (Features, Connection, Advanced)
- Server-controlled submenu items
- XPRA_CLIENT_CAN_SHUTDOWN environment variable
- Background image customization
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web-wireshark): remove xpra stop cleanup to avoid zombie processes
xpra stop can leave zombie processes and timeout. Instead, let xpra start
reuse the display directly (it will overwrite existing session).
Also added --file-transfer=no, --printing=no, --sound=no to disable
unneeded features.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web-wireshark): add fullscreen_button=false to default-settings.txt
Also remove --file-transfer/--printing/--sound from command line since
xpra doesn't support these options. Configure in default-settings.txt instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web-wireshark): update xpra background with GNS3 branding
- Replace default xpra background with GNS3 icon and modern gradient
- Update CSS to use SVG background image with cover sizing
- Change background color to gradient from #021d3a to linear gradient
- Improves visual integration with GNS3 web interface
* style: add GPLv3 headers with copyright to web_wireshark modules
Co-Authored-By: YueGuobin <yueguobin@gmail.com>
* feat(docker): use Alibaba Cloud Debian mirror for faster builds in China
Use mirrors.aliyun.com for Debian packages with correct paths for
both main repo (/debian) and security repo (/debian-security).
Co-Authored-By: YueGuobin <yueguobin@gmail.com>
* feat(web-wireshark): update xpra background styling and echo command
- Replace `echo -e` with `printf` for better POSIX compatibility in Dockerfile
- Update xpra HTML5 client background to use GNS3 icon with light gradient
- Change background color from dark blue to light gray for improved visibility
* fix(web-wireshark): use pkill to stop xpra sessions
Replace 'xpra stop :{display}' with 'pkill -f "xpra.*:{display}"' for more reliable session termination.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): start Wireshark in fullscreen mode
Add --fullscreen flag to Wireshark startup command to prevent window decorations and improve user experience.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): use carrier-grade NAT subnet to avoid conflicts
Change Docker network subnet from 172.28.0.0/16 to 100.64.1.0/24 to avoid conflicts with common private networks.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(web-wireshark): update subnet to /22 for 1000+ projects
Change Docker network subnet from 100.64.1.0/24 to 100.64.0.0/22 to support 1000+ projects (1022 available IPs). Update all documentation to reflect the new subnet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): replace CGNAT subnet with configurable private subnet
Replace the CGNAT address block (100.64.0.0/22) with a standard private
subnet (172.31.0.0/22) to avoid network access issues. Many networks and
ISPs block or cannot route CGNAT addresses.
Changes:
- Add WebWiresharkSettings to config schema with configurable subnet
- Read network_subnet from config, default to 172.31.0.0/22
- Add Web Wireshark configuration section to sample config
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): comment out dpi setting
Allow xpra to use default DPI settings for better display scaling.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): set DPI in Xvfb to prevent scaling warnings
Add -dpi 96 to Xvfb startup command to match xpra's expected DPI
and avoid "scaling problems" warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): remove custom Xvfb to use default Xorg-dummy
Remove --xvfb parameter to let xpra use the default Xorg-dummy driver,
which properly handles DPI changes when resize-display is enabled and
prevents DPI mismatch warnings.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* revert(web-wireshark): restore Xvfb configuration
Restore the Xvfb display server configuration for xpra sessions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): enhance xpra HTML5 default settings
Update xpra HTML5 configuration to disable additional unused features:
- audio, keyboard, mediasource, aurora, http-stream
- Improve readability using heredoc format instead of printf
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(api): add RBAC authentication to web wireshark WebSocket endpoint
- Add `has_privilege_on_websocket` dependency to enforce Link.Capture privilege
- Include current_user parameter in endpoint for user identification and logging
- Update endpoint documentation to reflect token requirement and privilege
- Add test example WebSocket URL in TEST.md for reference
* refactor(web-wireshark): add generic WebSocket proxy and disable xpra HTML
- Add websocket_to_websocket.py utility for binary WebSocket proxy
- Disable xpra HTML server with --html=no flag
- Update manager return value: url -> ws_url
- Simplify WebSocket proxy implementation in links.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web-wireshark): remove unnecessary sleep delays
Remove 2-second sleep delays after container start and xpra initialization.
Health checks and verification happen immediately, improving startup time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(agent): prevent blocking during project close
- Add 5s timeout for AgentService.checkpointer_conn.close()
- Optimize stop_all_sessions: single command instead of 100 docker exec calls
- Prevents indefinite hang when closing projects
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web-wireshark): return errors to client on startup failure
- Throw ControllerError when Web Wireshark startup fails
- Include detailed error messages from script stderr
- Support both ws_url and url response formats
- Client now receives proper error response instead of success
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web-wireshark): parallelize startup and remove unnecessary waits
- Parallel execution: container info query + xpra start
- Remove xpra list verification (unnecessary)
- Fire-and-forget Wireshark startup (no timeout wait)
- Startup time reduced from ~7s to ~1s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web-wireshark): add stop-container and delete-container commands
- Add stop-container command to stop container on project close
- Add delete-container command to delete container on project delete
- Enables proper container lifecycle management
- Containers are now stopped (not deleted) when project closes
- Containers are deleted when project is deleted
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(project): simplify close flow by removing redundant xpra session cleanup
Since docker stop with timeout=0 already force-kills all processes in the
container, explicitly stopping xpra sessions before stopping the container
is unnecessary. Remove the _cleanup_web_wireshark_xpra_sessions() call
to reduce subprocess overhead and simplify the close flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* perf(docker): force kill containers on stop by default
Change docker stop timeout from 10 seconds to 0 (immediate SIGKILL).
Web Wireshark containers don't need graceful shutdown since they have
no persistent state.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web-wireshark): enable WebSocket protocol for xpra connection
- Change xpra bind from --bind-tcp to --bind-ws for WebSocket support
- Enable HTML client with --html=on for xpra WebSocket server
- Pass binary subprotocol when connecting to xpra container
The xpra WebSocket server requires the 'binary' subprotocol during
handshake. Without it, the server returns 403 with message:
"client does not support 'binary' protocol".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web-wireshark): add WebSocket subprotocol negotiation support
Fix WebSocket proxy for xpra container by implementing proper subprotocol
negotiation. The xpra client requires the server to respond with the
negotiated subprotocol (binary) in the WebSocket handshake response.
Changes:
- Modified get_current_active_user_from_websocket to extract client's
requested subprotocols from Sec-WebSocket-Protocol header
- Updated websocket.accept() call to include negotiated subprotocol
- Enhanced websocket_proxy to support subprotocol parameter
- Improved logging for WebSocket connection debugging
This fixes the issue where xpra clients would immediately disconnect
after connection due to missing subprotocol in server response.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* chore(web-wireshark): remove verbose debug logging
Remove excessive debug logs from WebSocket proxy implementation while
keeping essential logs for troubleshooting:
- Keep: subprotocol negotiation, connection establishment, errors
- Remove: verbose step-by-step debugging information
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web-wireshark): translate Chinese comments and docs to English
- Translate all Chinese comments in project.py, link.py, and links.py to English
- Convert TEST.md and maunal-test.md documentation to English
- Remove obsolete IMPLEMENTATION_PLAN.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(docker): lock xpra version to 6.4.3 for reproducible builds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore(docker): improve Dockerfile with TZ, no-install-recommends, and labels
- Add TZ=UTC timezone setting
- Use --no-install-recommends to reduce image size
- Add LABEL metadata for maintainer and description
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(docs): rename and consolidate documentation
- Rename TEST.md to WEB_WIRESHARK.md for clearer naming
- Merge maunal-test.md content into main document under "Manual Testing" section
- Remove obsolete gns3_icon_black.svg
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(docker): add xpra-x11 package and remove --no-install-recommends
- Add xpra-x11 package required for seamless mode
- Remove --no-install-recommends to ensure all recommended packages are installed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(api): add capture file download endpoint
Add GET /{link_id}/capture/file endpoint to download PCAP capture files.
Supports downloading while capture is active (streaming).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web_wireshark): improve session cleanup and add known issues
- Add cleanup of existing processes before starting xpra session to prevent
"another window manager seems to be running" errors
- Stop all associated processes (xpra, wireshark, Xvfb) when stopping sessions
- Document known issues in WEB_WIRESHARK.md including JWT token security,
duplicate code, and other implementation concerns
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web_wireshark): add restart wireshark API endpoint
- Add POST /links/{link_id}/capture/wireshark/restart endpoint
- Add restart command to manage_wireshark.py CLI
- Add _restart_web_wireshark method in link.py controller
- Restart simply calls start_wireshark_session which handles cleanup
This allows users to recover after accidentally closing the Wireshark
window without having to stop and restart the entire capture.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add Web Wireshark business process documentation
Document the Web Wireshark feature including architecture diagrams,
business processes for capture start/stop, container lifecycle,
WebSocket connection flow, and session management.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web_wireshark): fix container network access and improve session cleanup
- Fix GNS3 server URL detection to use container gateway IP (172.31.0.1)
instead of localhost/127.0.0.1/0.0.0.0 which don't work from containers
- Add import socket module for gateway IP conversion
- Move urllib.parse import to file header (code style improvement)
- Add logging for Web Wireshark startup (capture stream URL, display, etc.)
- Fix X lock file cleanup to prevent "Server is already active" errors
- Use exec pkill to reduce zombie processes from docker exec bash
- Add _cleanup_x_lock() method to remove X lock files after stopping sessions
- Update link.py to always log subprocess stderr for debugging
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): avoid zombie pkill processes by using Docker API
Replace pkill commands with Docker API-based process killing to prevent
zombie process accumulation in Web Wireshark containers.
Changes:
- Add DockerHTTPClient.list_processes() method to query container processes
- Rewrite _kill_process_tree() to use Docker API instead of pkill
- Unify all process cleanup to use _kill_process_tree() method
- Add logging for killed processes (count and PIDs)
- Include fallback to pkill if Docker API fails
This prevents the accumulation of zombie pkill processes that occurred
when using bash -c "pkill -9 -f pattern" commands.
Testing: Started and stopped multiple capture sessions, verified no new
pkill zombie processes are created during cleanup.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): use docker-init and cleanup socket files
Enable Docker init system (tini) as PID 1 and clean up xpra socket
files when stopping sessions to prevent zombie processes and leftover
sockets.
Changes:
- Add "Init": True to container host_config to use docker-init (tini)
- Extend _cleanup_x_lock() to remove xpra socket files
* /run/user/1000/xpra/{display}/socket
* /run/user/1000/xpra/*-{display}
* /home/gns3/.xpra/*-{display}
Benefits:
- docker-init (tini) automatically reaps orphan processes, eliminating
zombie process accumulation (tested: 53 zombies -> 0 zombies)
- Socket cleanup prevents xpra list from showing UNKNOWN sessions
- Cleaner container state after stopping sessions
Testing:
- Started and stopped 3 capture sessions
- Verified 0 zombie processes after stopping
- Verified xpra list shows "No xpra sessions found" (no UNKNOWN)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(web_wireshark): add comprehensive CLI script documentation
Add detailed module docstring to manage_wireshark.py explaining:
- Script purpose: CLI tool for manual management, debugging, and testing
- Important note: Use WebWiresharkManager directly for programmatic access
- Usage examples for all commands (start, stop, restart, stop-all, delete)
- Available commands list with descriptions
- Output format specification (JSON to stdout/stderr)
- Help information for getting command-specific usage
This clarifies that the script is intended as a CLI utility, not for
subprocess calls from within GNS3 server code.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web_wireshark): use direct API calls instead of subprocess
Replace subprocess calls to manage_wireshark.py with direct API calls
to WebWiresharkManager, eliminating subprocess overhead and JSON parsing.
Changes:
- Add import for WebWiresharkManager
- Refactor _start_web_wireshark() to use direct API call
- Refactor _stop_web_wireshark() to use direct API call
- Refactor _restart_web_wireshark() to use direct API call
Benefits:
- Code reduction: 78 lines (-68%)
- Better performance: No subprocess creation overhead
- Better logging: Manager logs directly to GNS3 logging system
- Simpler error handling: Direct exceptions instead of return codes
- No JSON parsing: Direct Python objects
- Resource cleanup: Added finally blocks to ensure manager.close()
Testing:
- All Web Wireshark operations work correctly
- Logs now appear in GNS3 server logs instead of stderr
- Error handling improved with proper exception propagation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): resolve circular import with delayed imports
Fix circular import error by moving WebWiresharkManager import from
module level to function level (delayed import).
Circular dependency was:
link.py → WebWiresharkManager → Controller → link.py
Solution:
- Remove top-level import of WebWiresharkManager
- Add delayed imports in each method that uses it:
* _start_web_wireshark()
* _stop_web_wireshark()
* _restart_web_wireshark()
This allows the controller module to fully initialize before importing
WebWiresharkManager, breaking the circular dependency.
Error before fix:
ImportError: cannot import name 'Controller' from partially initialized
module 'gns3server.controller' (most likely due to a circular import)
Testing:
- Successfully imports Link module
- GNS3 server starts without import errors
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: move imports to module level and remove Controller dependency
Remove circular dependency between link.py and manager.py by:
1. Remove Controller import from manager.py
- Manager no longer imports Controller
- URL detection now relies on Config or default only
- link.py passes capture_stream_url to manager
2. Move WebWiresharkManager import to module level in link.py
- No longer need delayed imports since no circular dependency
- Clean, standard Python import pattern
3. Remove redundant Config import in ensure_network()
- Config was already imported at module level
Changes:
- manager.py: -24 lines (removed _get_gns3_url_from_controller and redundant import)
- link.py: -30 lines net reduction after moving import to top
Testing:
- All imports work without circular dependency errors
- GNS3 server starts successfully
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(docker_client): use text response for list_processes API
Docker API /containers/{id}/top returns plain text, not JSON.
The generic _request method auto-parses JSON which caused:
"'dict' object has no attribute 'strip'"
Fix by using session.get() directly with response.text()
instead of the generic _request method.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): use correct capture stream URL endpoint
Remove passing capture_stream_url from link.py to manager.py.
Manager.py auto-detects URL using correct endpoint:
/v3/projects/{project_id}/links/{link_id}/capture/stream
This endpoint supports JWT authentication, unlike the compute URL
(/v3/compute/...) which requires compute credentials.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): use container-local PIDs for process killing
- Docker API returns host PIDs, not container PIDs - use pgrep inside
container to get correct PIDs for kill
- Fix list_processes to parse Docker API JSON response correctly
- Remove unnecessary exec prefix in shell commands
- Add logging for debugging process killing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* perf(web_wireshark): optimize process killing with single pgrep call
Replace sequential _kill_process_tree calls with a new _kill_process_tree_batch
method that combines all patterns into a single regex. This reduces docker exec
calls from 8 to 1, improving performance from ~8 seconds to ~0.9 seconds.
Changes:
- Add _kill_process_tree_batch() method with combined regex pattern matching
- Update start_wireshark_session() to use batch cleanup
- Update stop_wireshark_session() to use batch cleanup
- Update stop_all_sessions() to use batch cleanup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): disable HTML5 client to improve xpra startup speed
Change --html=on to --html=off to disable the xpra HTML5 client interface.
This reduces xpra startup time from ~6.4s to ~2.9s (55% improvement) while
keeping the WebSocket server functional for browser connections.
The HTML5 client is not needed as we only require the WebSocket endpoint
for remote display forwarding.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): optimize container health check using Docker built-in status
Replace manual docker exec ping with Docker's built-in health check status
to reduce container startup latency by ~1 second.
Changes:
- Use container["Health"]["Status"] instead of manual ping check
- Skip health check for containers with "healthy" or "starting" status
- Only verify containers with "unhealthy" status
- Keep manual health check for newly started containers
This reduces the container verification time from ~1s to near-zero
for healthy running containers while maintaining safety for unhealthy ones.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): get gateway IP from Docker API instead of container exec
Replace slow docker exec method with fast Docker Network API call to get
gateway IP. This reduces gateway detection from ~850ms to ~1ms (1000x faster).
Changes:
- Use docker.get_network() API to get gateway from IPAM config
- Keep container exec methods as fallback if Docker API fails
- Remove container_id requirement (not needed for Docker API method)
The Docker network gateway is shared by all containers in the network,
so querying the network is more efficient than querying each container.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web_wireshark): remove unreliable nameserver fallback for gateway detection
Remove the fallback method that reads /etc/resolv.conf nameserver as gateway.
This method is unreliable because:
- nameserver is not necessarily the gateway (could be upstream DNS)
- Many systems use 127.0.0.53 (systemd-resolved) or 127.0.0.1
- Even when not local, it could be public DNS (8.8.8.8, 1.1.1.1)
The current fallback strategy is sufficient:
1. Docker Network API (fast, reliable)
2. /proc/net/route (standard gateway detection)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): use host perspective for process killing (37x faster)
Replace docker exec with host perspective process management for killing
container processes. This reduces process cleanup from ~850ms to ~23ms.
Key optimization:
- Get container init PID using docker inspect (fast)
- Use pgrep -P <init_pid> to find child processes from host perspective
- Kill processes directly using host PID (no docker exec needed)
Performance improvements:
- Process finding: 850ms → 23ms (37x faster)
- Process killing: 850ms → <1ms (850x faster)
- File checking: 850ms → 0.003ms (280,000x faster)
Fallback to docker exec method if host perspective fails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): use host perspective for file cleanup (891x faster)
Replace docker exec with direct filesystem access from host perspective
for cleaning up X lock files and xpra sockets. This reduces cleanup time
from ~890ms to ~1ms (891x faster).
Key optimization:
- Access /proc/<container_pid>/root/ directly from host
- Use os.remove() and glob.glob() instead of docker exec rm -f
- Fallback to docker exec if host perspective fails
This complements the earlier optimization for process killing, further
reducing startup time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Revert "perf(web_wireshark): use host perspective for file cleanup (891x faster)"
* fix(web_wireshark): recursively kill all descendant processes to prevent orphans
Previous implementation only killed direct children of container init using
`pgrep -P <init_pid>`, but xpra spawns child processes (Xvfb, pulseaudio,
ibus-daemon) that become grandchildren and were not being terminated.
This fix walks the entire process tree recursively to find and kill all
descendant processes, ensuring complete cleanup without orphans.
Performance: ~20-40ms (only 10-20ms slower than previous 23ms, but ensures
thorough cleanup).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* docs(web_wireshark): add comprehensive startup/shutdown performance metrics
Add detailed performance characteristics section documenting:
- Startup performance breakdown (before/after optimization)
- Shutdown performance breakdown (before/after optimization)
- First startup vs subsequent startup comparison
- Measured production data
- Key optimization techniques
Performance improvements: 67% faster startup, 78% faster shutdown,
zero orphan processes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): ensure container stops on project close
Remove dependency on _web_wireshark_container_created flag which gets
reset when project is reloaded, causing container to not stop on project close.
Now directly attempts to stop container on every project close. If container
doesn't exist, the script handles it gracefully. This is simpler and more
reliable than maintaining a flag.
Also removed unnecessary _cleanup_web_wireshark_xpra_sessions() call since
stopping the container automatically terminates all xpra sessions inside.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): ensure container deletion on project delete
Remove dependency on _web_wireshark_container_created flag from
_cleanup_web_wireshark_container() to ensure container is deleted
when project is deleted, even if project was reloaded and flag was reset.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(web_wireshark): remove unused _web_wireshark_container_created flag
This flag was set but never read for any conditionals since we changed
the stop/delete methods to directly attempt the operation. It's purely
redundant code that adds confusion.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): skip unnecessary cleanup using fast host perspective check
Add _check_residuals_exist() function that uses host perspective (~20ms)
to check if residual processes or socket files exist before cleanup.
Returns (has_process_residuals, has_socket_residuals) tuple to allow
selective cleanup - if only sockets need cleaning, skip the slower
process tree killing.
For new containers with no residuals, this saves ~3 seconds of
unnecessary docker exec calls.
Socket cleanup always uses docker exec for safety (avoiding accidental
host filesystem deletion from /proc/<pid>/root/ path errors).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(web_wireshark): increase container exec timeout from 5s to 10s
xpra start with Xvfb initialization can take longer than 5 seconds in Docker containers, causing timeout failures. Increasing timeout to 10 seconds to allow sufficient startup time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* perf(web_wireshark): optimize cleanup and document docker exec limitations
- Combine X lock and xpra socket cleanup into single docker exec call
Reduces exec calls from 2 to 1 per stop operation, improving performance
when stopping multiple capture sessions.
- Document Docker exec performance limitations with test data showing
parallel exec is 42% slower than serial due to Docker daemon's
internal queuing mechanism.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(links): prevent AssertionError in stream_pcap during rapid stop_capture
Fix race condition where stream_pcap checks link.capturing (True) but
link.capture_node becomes None before accessing link.compute.
This happens when stop_capture() is called and rapidly cleans up
_capture_node while WebSocket requests are still processing.
Now check both capturing and capture_node to ensure capture is still active.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(links): prevent AssertionError in stream_pcap during rapid stop_capture
Fix race condition where stream_pcap checks link.capturing (True) but
link.capture_node becomes None before accessing link.compute.
This happens when stop_capture() is called and rapidly cleans up
_capture_node while WebSocket requests are still processing.
Now check both capturing and capture_node to ensure capture is still active,
and log at DEBUG level since this is expected behavior during rapid stop.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web_wireshark): load container config from settings
- Load memory, cpus, and pids_limit from WebWireshark config section
- Apply config only on container creation (_start_web_wireshark)
- Skip config on restart (_restart_web_wireshark) as container exists
Users can now configure container resources in gns3_server.conf:
[WebWireshark]
memory = 4g
cpus = 2.0
pids_limit = 2000
If not configured, defaults (2g, 1.0, 1000) are used.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat(web_wireshark): add container statistics to /v3/statistics endpoint
Add Web Wireshark container monitoring to the statistics API for
better visibility into packet capture sessions.
Changes:
- Create new stats.py module with collect_webwireshark_stats()
* Collects container info (status, project, active sessions)
* Gets resource limits (memory, CPU, PIDs) from container config
* Gets resource usage via docker stats (memory, CPU, PIDs)
* Properly closes aiohttp connections to avoid leaks
- Update /v3/statistics endpoint to include webwireshark data
* total_containers: Total number of Web Wireshark containers
* running_containers: Number of containers currently running
* active_sessions: Total active capture sessions
* containers: Array with per-container details
- Update statistics-api.md documentation
* Change URL from /v1/statistics to /v3/statistics
* Add webwireshark field descriptions and examples
* Add dashboard integration for Web Wireshark monitoring
Example response:
{
"webwireshark": {
"total_containers": 1,
"running_containers": 1,
"active_sessions": 2,
"containers": [{
"project_id": "...",
"project_name": "test",
"container_id": "6edc9029bac0",
"status": "running",
"memory_limit": "4.0 GB",
"cpu_limit": "4.0",
"pids_limit": 4000,
"memory": "535.7MiB / 4GiB",
"cpu": "0.29%",
"pids": 124
}]
}
}
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor(project): use WebWiresharkManager directly instead of subprocess
Replace subprocess calls to manage_wireshark.py with direct
WebWiresharkManager method calls in project.py. This eliminates
unnecessary process overhead and maintains consistent usage pattern
with link.py.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(logging): use %-formatting instead of f-strings in WebWireshark methods
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(web_wireshark): use info level log when container not found
Change log level from warning to info when container doesn't exist
during stop/delete operations, and fix f-string without placeholders.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(logging): lower log level for client disconnection
Change log level from warning to debug when client possibly
disconnects, as this is normal behavior when users close
browser tabs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(linting): resolve ruff warnings and errors
- Remove unused variable proc (fire-and-forget subprocess)
- Remove duplicate nodes property definition
- Remove extraneous f-prefix from f-strings without placeholders
- Change bare except to except Exception
- Remove unused imports (sys, asyncio, json)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web_wireshark): improve error message when Docker image not found
When creating a container fails due to missing image, provide helpful
error message with docker pull command and local build instructions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(schema): add wireshark field to Link schema
Add wireshark boolean field to Link Pydantic schema so it is
included in API responses when Web Wireshark session is active.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(link): add wireshark state tracking
Track whether Web Wireshark is running on a link by adding
_wireshark boolean property, updated on start/stop operations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): add session abort functionality
Add ability to abort streaming chat sessions via REST API.
Changes:
- Add abort flag to MessagesState for tracking abort requests
- Add session_id to state for abort event correlation
- Add _abort_flags dict and check/set/clear functions in gns3_copilot.py
- Add abort_handler_node to generate aborted tool messages
- Modify should_continue to route to abort_handler_node when aborting
- Add abort_session() method in AgentService
- Add POST /sessions/{session_id}/abort API endpoint
- Clear abort flag at stream start
When abort is triggered during streaming:
- If LLM has tool_calls pending, abort_handler_node generates
aborted tool messages to maintain checkpoint consistency
- Prevents "insufficient tool messages" error on resume
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(chat): send tool_end event when stream is aborted
When a stream is aborted during tool execution, yield proper tool_end
events for aborted tools instead of a generic abort event. This maintains
compatibility with the frontend's expected tool_start/tool_end flow.
Changes:
- Add stream_aborted tracking flag
- After stream loop, check abort flag and yield tool_end events
- Add "abort" to ChatResponse type enum (unused but available)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(web_wireshark): add gns3-wireshark-setup command for Docker image setup
Add a new entry point script that allows users to setup the Web
Wireshark Docker image with a single command:
pip install gns3-server && gns3-wireshark-setup
The script will:
1. Try to pull gns3/web-wireshark:latest from Docker Hub
2. If pull fails, build the image locally using the included Dockerfile
3. Show raw docker pull/build output for full visibility
Files changed:
- Add setup_wireshark_image.py (new entry point script)
- Update pyproject.toml (add gns3-wireshark-setup entry point)
- Update documentation (README.md, WEB_WIRESHARK.md, web-wireshark-business-process.md)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(appliance): add tags field support for appliances and templates
- Add tags field to ApplianceV1_6 and ApplianceV8 schemas
- Add tags propagation from appliance config to template
- Simplify VPCS builtin template tags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fix test in test_link.py
* Fix link.py after failed tests
* feat(copilot): add device skills system for LLM context injection
- Add skills module with registry and DeviceSkillsTool
- Skills organized by vendor/series for easy extensibility
- Support device_type, category (device/protocol/feature), operation (config/diagnosis)
- First implementation: VPCS skill (gns3_vpcs_telnet)
- Skills tool integrated into teaching_assistant and lab_automation modes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(vpcs): change prompt detection log from warning to debug
The "VPCS prompt not clearly detected" message is not an error,
connection works fine. Change to debug level to reduce noise.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(memory): add uBridge permission issue documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(copilot): include link_id in links_summary output
Return link_id in the links_summary method so that the AI can
identify which link to analyze when using the packet capture tool.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add packet capture analysis tool
Add PacketCaptureTool that allows AI to analyze packets from an active
GNS3 capture. The tool downloads capture files from the GNS3 server
and runs tshark analysis to help users understand network traffic.
Features:
- Download capture file from /capture/file endpoint
- Run tshark with custom arguments for flexible analysis
- Support analyzing specific packets (e.g., "explain packet #42")
- Support protocol statistics, traffic analysis, and expert info
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(copilot): use shlex.split to properly parse quoted tshark arguments
tshark_args may contain quoted filter expressions like "-Y \"frame.number == 24\"".
Using plain str.split() breaks these quoted arguments, causing tshark warnings
about conflicting display filters. Use shlex.split() to correctly parse quoted
arguments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): simplify PacketCaptureTool to accept only packet_number
Instead of exposing complex tshark arguments to the LLM, the tool now
accepts a simple packet_number parameter and internally constructs the
tshark command with verbose output. This prevents the LLM from generating
incorrect tshark parameters while still providing detailed packet analysis.
Changes:
- Remove tshark_args and max_lines parameters
- Accept only packet_number as input
- Internal command: tshark -r <file> -Y "frame.number == N" -V
- Returns complete packet structure without line limits
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: add CC BY-SA 4.0 license headers to documentation files
Add SPDX license headers referencing docs/LICENSE file to all markdown
and HTML documentation files in the docs directory.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add topology planner skill
Add new skill for automatic network lab topology planning:
- IOU as default image, 10.0.0.0/8 IP range, max 10 nodes
- Node naming convention: R/S/PC + number
- 7-step workflow for create/rename/link/start/verify/config
- IP allocation rules and troubleshooting guide
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add node positioning rules to topology planner skill
Add grid-based positioning for GNS3 nodes:
- Minimum 250px distance between nodes
- Grid layout: 4 columns, 300x250px spacing
- Formula: x = -400 + col * 300, y = -200 + row * 250
- Update workflow params_required to include x, y coordinates
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): remove unused helper functions from topology planner skill
Delete Python helper functions that cannot be serialized to JSON:
- calculate_node_positions()
- get_position_for_node()
- allocate_subnet()
- allocate_ip()
- TOPOLOGY_CREATION_STEPS (duplicate of workflow in skill dict)
LLM should use formula descriptions in skill to calculate positions/IPs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): add topology_planner workflow to lab automation prompt
Add device_skills tool to AVAILABLE TOOLS table.
Add TOPOLOGY PLANNING WORKFLOW section explaining:
- How to query topology_planner skill
- Default conventions (IOU, 10.0.0.0/8, naming rules, position formula)
- 7-step workflow for topology creation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(copilot): support name parameter in gns3_create_node tool
- Add optional 'name' field to node creation, allowing direct naming
- Update Node constructor to pass name parameter
- Remove separate rename step (step_3) from topology planner workflow
- Renumber workflow steps: 1-2-3-4-5-6 (skipping old step_3 rename)
This eliminates the need for a separate gns3_update_node_name_tool call
when creating nodes with predefined names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(copilot): update topology workflow to 6 steps
Remove rename step since name can be set directly in create_gns3_node.
Workflow changed from 7 steps to 6 steps.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): replace grid positioning with topology-based layout
Redesign node positioning rules to follow classic network topologies:
- Star: hub at center, spokes radiating outward
- Ring: nodes in circular arrangement
- Bus: linear chain of nodes
- Mesh: grid pattern for interconnected nodes
- Hierarchical: three-tier (Core → Distribution → Access)
- Linear P2P: point-to-point WAN links in a line
Remove old grid formula. Update prompt and workflow to reflect new approach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs(copilot): add note about combining topology types
LLM can mix topology types as needed, e.g., star + linear_p2p for WAN segments.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): remove language matching rules from prompts
Remove language matching rules that cause inconsistent responses:
- "User writes in Chinese → Respond in Chinese"
- "User writes in English → Respond in English"
These created ambiguity and led to inconsistent language behavior.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): remove Chinese from response template
Replace mixed Chinese/English headers with English only:
- "操作总结 / Operation Summary" → "Operation Summary"
- "详细信息 / Details" → "Details"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(copilot): remove Chinese mentions from prompts
Remove references to "Chinese" language in title_prompt.py:
- "Generates concise Chinese or English titles" → "Generates concise titles"
- "If the content is predominantly in Chinese, generate a Chinese title" → removed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(copilot): use short_name for link labels and support short port names
- Match ports by both name and short_name for flexibility
- Use short_name (e.g. "e0/0") instead of full name (e.g. "Ethernet0/0")
for link labels, improving visual clarity in dense topologies
* feat(topology): replace hardcoded interface names with dynamic placeholders
- Update topology planner skill template to use {short_name} placeholder
- Allows dynamic interface name generation based on device type
- Improves template flexibility for different network device configurations
* refactor(topology): use node-pair IP format and hyphenated naming
- Use 10.0.{node_pair}.x format for P2P links (e.g., 10.0.12.x for R-1-R-2)
- Change node naming to hyphenated format: R-1, R-2, SW-1, PC-1
- Use {short_name} as placeholder for port names in output template
- Remove unused IP_SUBNET_POOL constant
- Simplify ip_planning rules to intuitive format description
* fix(web_wireshark): raise minimum Docker API version to 1.44
Docker daemon requires API version 1.44+, so the minimum
supported version should match rather than defaulting to 1.40.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(web_wireshark): call ensure_network in start_wireshark_session
Ensure Docker network exists before creating container, so that
Web Wireshark works when started via API without going through CLI.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(agent): improve Docker image setup with network error detection
- Add `is_network_error()` function to detect network-related failures in Docker pull output
- Modify `pull_image()` to capture output and return success status along with output
- Enhance main logic to detect network errors and skip local build when Docker Hub is inaccessible
- Provide helpful suggestions for network issues (Docker mirror, VPN, manual image transfer)
- Improve error messages to differentiate between network failures and other errors
* feat(docs): add Ubuntu 24.04 development setup guide
Add a comprehensive development environment setup guide for Ubuntu 24.04. The guide includes steps to install dependencies via PPA, configure Docker with mirror accelerators for users in mainland China, set up user permissions, and run the server from source with a Python virtual environment. This provides a clear, step-by-step reference for new contributors and developers.
* feat(docs): add pip mirror note for China mainland users
Add a comment in the development setup documentation suggesting the use of the Aliyun PyPI mirror for users in China mainland to improve installation speed and reliability. This helps overcome network restrictions and slow downloads from the default PyPI repository.
* feat(docs): add LVM root partition expansion guide
Add optional section to development setup documentation with instructions for expanding the root partition when using LVM. This helps developers resolve low disk space issues by utilizing unallocated space in the volume group. The guide includes commands to check LVM status, extend the logical volume, and verify the changes.
* feat(docs): add tshark to development setup dependencies
Add tshark to the apt install command in the development setup documentation. Tshark is required for packet capture functionality in GNS3, ensuring the development environment has all necessary tools for network analysis and debugging.
* feat: add GNS3 documentation skill with standardized structure
Add new documentation skill file defining standards for GNS3 technical documentation. The skill establishes a structured approach focusing on architecture diagrams, flow diagrams, and text descriptions while prohibiting code examples and user scenarios. This ensures consistent, high-quality documentation across the GNS3 ecosystem.
* feat(docs): update documentation skill to focus on server technical docs
Update the GNS3 documentation skill to specifically target server technical documentation under the docs/ directory. The revised standard emphasizes high-level understanding over implementation details, using ASCII diagrams for architecture and business processes, API endpoint tables, and measured performance data. Code specifics are intentionally omitted, directing readers to the codebase for implementation details.
* feat(docs): rewrite documentation skill and statistics API doc
- Rewrite gns3-documentation skill to match actual server-side doc style:
focus on architecture/flow diagrams, API data, skip code details
- Switch diagram standard from ASCII to Mermaid (GitHub native rendering)
- Rewrite statistics-api.md with Mermaid architecture and sequence diagrams,
add missing webwireshark container fields (memory_limit, cpu_limit, pids_limit),
remove speculative content
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(docs): update VNC WebSocket console documentation with Mermaid diagrams
- Replace ASCII diagrams with Mermaid flowcharts for better visualization
- Clarify connection flow between browser, controller, compute, and VNC server
- Update authentication details and endpoint descriptions
- Add missing documentation for packet capture workflow
- Improve overall readability and maintainability
* docs: add AI disclaimer to documentation files
Add a standardized disclaimer to multiple documentation files indicating that the content has been organized by AI with reference to actual code. The disclaimer warns users that AI can make mistakes and advises verification against the source code when in doubt. This improves transparency about the documentation's origin and encourages careful usage.
* feat(docs): update chat API documentation with new features and clarifications
- Update title from "Design Document" to reflect current implementation status
- Add new features: session abort, copilot modes (teaching_assistant, lab_automation_assistant), session pinning
- Enhance architecture diagram with LangGraph StateGraph details including abort_handler_node, title_generator_node, and conditional edges
- Clarify statistics tracking: add ai_response_counted flag, filter title_generator_node from LLM counts, explain incremental token counting
- Improve documentation accuracy for real-time statistics collection and token calculation methods
* feat(docs): restructure command security documentation with visual workflows
- Replace verbose implementation details with concise architecture overview
- Add Mermaid diagrams to visualize command filtering and multi-line expansion flows
- Simplify configuration instructions and remove redundant examples
- Consolidate file structure and function reference tables for clarity
- Maintain all security principles while improving readability and maintainability
* feat(context): refactor context window management documentation for clarity
- Reorganize documentation with improved structure and visual diagrams
- Add Mermaid diagrams to illustrate architecture and trimming process
- Simplify content while maintaining technical accuracy
- Update token counting and trimming strategy explanations
- Enhance readability with better formatting and component tables
* feat(docs): update LLM model configs documentation
- Change config column type from JSONB to JSON (JSONB on PostgreSQL)
- Update provider table to mark base_url as required with planned optional status
- Add note about base_url being currently required in API schema
- Clarify GET own configs endpoint returns plain array
- Add copilot_mode field to update request schema
- Document update limitations for context_strategy and copilot_mode fields
* feat(docs): add GNS3StartNodeQuickTool and update node creation examples
- Add documentation for new `GNS3StartNodeQuickTool` (`start_gns3_node_quick`) that starts nodes without waiting for boot completion
- Update node creation example to include optional `name` field in template placement
- Clarify dynamic wait time strategy for `GNS3StartNodeTool` and contrast with quick tool
- Update tool file structure to reflect new configuration, display, and packet capture tools
- Fix truncated line in suspend tool documentation
* feat(docs): add comprehensive documentation structure with CC BY-SA 4.0 license
Add initial documentation directory with detailed README.md that outlines:
- Dual license structure (CC BY-SA 4.0 for docs, GPLv3 for code)
- Complete directory structure for features, AI Copilot, and bugs
- Feature documentation covering Controller+Compute setup, Statistics API, VNC WebSocket console, and Web Wireshark
- AI Copilot implemented features including Chat API, LLM model configs, command security, and multi-vendor device support
This provides organized technical documentation for the GNS3 server project with proper licensing and feature coverage.
* docs: update multi-vendor device support documentation
- Simplify vendor support table by removing redundant platform column
- Add VPCS as a simulator in status column
- Improve VPCS driver diagram with Mermaid syntax and detailed components
- Document VPCS-specific Netmiko parameters (fast_cli, global_delay_factor)
- Update VPCS tool usage example with connection options structure
- Remove outdated Nornir configuration approaches, reference current implementation
- Add file reference for VPCS tools location
- Clean up documentation structure for better readability
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: YueGuobin <yueguobin@gmail.com>
Co-authored-by: Jeremy Grossmann <grossmj@gns3.net>
FileResponse does not properly include CORS headers when served from
a different origin. This fix manually adds the Access-Control-Allow-Origin
header based on the request origin.
Fixes CORS policy errors when accessing symbol files from frontend
applications running on localhost:4200 or other origins.
Closed project nodes don't have status info in topology JSON.
Add open_project_nodes and closed_project_nodes counts to
help clarify why by_status may be empty.
Open projects store Node/Link objects, but closed projects store
dictionaries loaded from topology JSON. This fix checks the type
before accessing attributes.
Return aggregated statistics:
- computes: per-compute CPU/memory/disk stats (existing)
- projects: total, opened, closed counts
- nodes: total count with breakdown by type and status
- links: total count with capturing count
Add comprehensive link creation templates documentation covering:
- Batch link creation workflow with HITL confirmations
- Link template schema with pattern-based connectivity
- Common topology patterns (Spine-Leaf, Ring, Mesh, Star, Three-tier)
- Intelligent port allocation strategies (round-robin, optimized)
- Performance benchmarks showing 99.9% token savings for large topologies
- Complete workflow example combining all three template systems
Add comprehensive documentation for LLM model providers:
- Provider list with default base URLs and requirements
- Examples for different providers (OpenAI, Anthropic, Ollama, Azure)
- Guidelines on when to specify base_url
- Future enhancements section for optional base_url field
Add error_handler utility to detect and format HTML error responses
from misconfigured API base URLs. When the API returns HTML (indicating
configuration issues), users now see a helpful message instead of raw
HTML content.
This change makes AI Copilot features optional to reduce installation
size and support restricted environments.
Changes:
- Split AI dependencies into ai-requirements.txt
- Add ai-copilot optional dependency in pyproject.toml
- Add import protection in gns3server/agent/__init__.py
- Return 501 for AI endpoints when dependencies not installed
- Add gns3server-uninstall-ai-copilot command for cleanup
- Update README with installation and uninstallation instructions
Installation:
- Basic: pip install gns3-server
- With AI: pip install gns3-server[ai-copilot]
- Development: pip install gns3-server[ai-copilot,dev]
Uninstallation:
- gns3server-uninstall-ai-copilot
Refactored test assertions for Huawei CE, Ruijie, and VPCS telnet drivers to compare only class names instead of full module paths. This change reduces test brittleness when classes are imported via different module paths while maintaining validation of correct class registration in CLASS_MAPPER and CLASS_MAPPER_BASE.
Refactor test assertions to compare classes by module and name instead of direct object comparison. This ensures tests remain reliable when classes are imported via different paths, preventing false failures due to import variations. Changes applied to Huawei CE, Ruijie, and VPCS telnet driver tests.
Changed test assertions from `assertIs` to `assertEqual` for class mapper comparisons in Huawei CE, Ruijie, and VPCS telnet driver tests. This ensures proper equality checking rather than identity checking, which is more appropriate for class comparisons in these test cases.
remove unused reserved_jsonb fields
Remove the three reserved JSONB fields (reserved_jsonb_1, reserved_jsonb_2, reserved_jsonb_3) from the llm_model_configs
table. These fields were planned for future use but are no longer needed.
assertIs instead of assertEqual for class comparison
Fix test failures in custom Netmiko driver tests by using assertIs instead
of assertEqual when comparing class objects registered in CLASS_MAPPER.
The issue occurred because test files add project root to sys.path, allowing
the same module to be imported with different paths (e.g., gns3_copilot...
vs gns3server.agent.gns3_copilot...). assertEqual compares class __module__
attributes which differ based on import path, while assertIs checks object
identity which correctly identifies them as the same class.
Modified files:
- test_huawei_ce.py
- test_ruijie_telnet.py
- test_vpcs_telnet.py
Update the import statement for Nornir from `nornir.core.nornir` to `nornir.core` to align with the latest Nornir library structure and avoid potential import errors. This ensures compatibility with updated Nornir versions.
Remove all SPICE WebSocket-related code due to frontend dependency issues
with spice-html5 library (missing RSAKey/BigInteger implementations).
Changes:
- Remove start_spice_websocket_console() from BaseNode
- Remove SPICE WebSocket endpoints from QEMU and Docker compute APIs
- Remove SPICE WebSocket proxy endpoint from controller API
- Remove WebSocket subprotocol handling from authentication layers
- Remove SPICE documentation
The SPICE console type remains functional for direct connections,
but WebSocket proxy support has been removed.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add WebSocket-based console support for SPICE protocol, enabling
browser-based graphical console access with enhanced features
like clipboard sharing, USB redirection, and audio streaming.
Changes:
- Add start_spice_websocket_console() method in BaseNode for SPICE
WebSocket to TCP bridging with bidirectional binary forwarding
- Add /console/spice WebSocket endpoints in QEMU and Docker compute APIs
- Add /console/spice WebSocket proxy endpoint in controller API
- Add comprehensive API documentation in docs/features/
Supported console types:
- spice: Basic SPICE protocol support
- spice+agent: SPICE with spice-vdagent for enhanced features
Architecture:
- Browser WebSocket → Controller (JWT + RBAC) → Compute (Basic Auth)
- No external websockify processes required
- Consistent with existing VNC WebSocket implementation
Add VNC console WebSocket endpoints for Docker and QEMU nodes:
- Add /console/vnc WebSocket endpoint to compute API (Docker & QEMU)
- Add /console/vnc WebSocket endpoint to controller API
- Implement start_vnc_websocket_console() in BaseNode
- Forward VNC WebSocket traffic between controller and compute layers
The implementation provides bidirectional WebSocket to TCP forwarding
for VNC protocol (RFB) connections, allowing browser-based VNC console
access to containers and VMs.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Configure tiktoken cache directory to isolate encoding files
- Add logging and timing for tiktoken initialization process
- Make Huawei CE and Ruijie Telnet device registration idempotent
- Add duplicate registration prevention with global flags
- Add logging for device type registration status
- Update .gitignore to exclude tiktoken cache files
Add detailed bug report documenting a race condition in the telnet server's broadcast logic. The bug occurs when a client disconnects while the server is iterating through connections to broadcast data, causing an uncaught OSError from getpeername() call.
Key details included:
- Error logs showing OSError: [Errno 107] Transport endpoint is not connected
- Architecture diagram illustrating the telnet proxy server setup
- Root cause analysis showing the race condition timeline
- Problematic code location in telnet_server.py line 305
- Exception hierarchy explanation showing why OSError isn't caught
- Impact assessment and proposed solutions
This documentation will help track and resolve the issue where client disconnections during broadcast cause unhandled exceptions.
- Catch OSError alongside ConnectionError in connection processing to handle more network errors
- Move client_info retrieval inside try block to prevent AttributeError on failed connections
- Replace bare except with specific exceptions (OSError, ConnectionError, asyncio.TimeoutError)
- Improve error logging to include specific exception details and client information
Fixes two critical issues in telnet server when clients rapidly
connect/disconnect during broadcast operations:
1. **OSError [Errno 107]**: Transport endpoint not connected
- Root cause: getpeername() called outside try block
- Fix: Move getpeername() inside try block and catch OSError
- Expand exception handling to include OSError and TimeoutError
2. **KeyError**: Double deletion from connections dictionary
- Root cause: Connection deleted in broadcast loop, then deleted
again in top-level exception handler
- Fix: Use dict.pop(key, None) instead of del dict[key]
**Changes**:
- Line 216: Add OSError to top-level exception handler
- Line 227-228: Use pop() to avoid KeyError on double deletion
- Line 305-316: Move getpeername() inside try block, expand
exception types, use pop() for safe deletion
**Impact**:
- Prevents unhandled exceptions from propagating to asyncio event loop
- Ensures proper resource cleanup even with race conditions
- No resource leaks or zombie connections
- Long-lived clients unaffected by rapid client disconnects
**Test Script**:
- Added stress test script to reproduce the issue
- Supports IOU-L3, VPCS, and generic device types
- Rapid clients send broadcast-triggering commands (show/run/OSPF)
**Related**: Fixes bug documented in docs/bugs/telnet-server-connection-race-condition.md
Add detailed bug report documenting a race condition in the telnet server's broadcast logic. The bug occurs when a client disconnects while the server is iterating through connections to broadcast data, causing an uncaught OSError from getpeername() call.
Key details included:
- Error logs showing OSError: [Errno 107] Transport endpoint is not connected
- Architecture diagram illustrating the telnet proxy server setup
- Root cause analysis showing the race condition timeline
- Problematic code location in telnet_server.py line 305
- Exception hierarchy explanation showing why OSError isn't caught
- Impact assessment and proposed solutions
This documentation will help track and resolve the issue where client disconnections during broadcast cause unhandled exceptions.
Optimize GNS3StartNodeTool with device-type-aware wait time calculation
to significantly reduce startup time for fast devices (VPCS, IOU).
Changes:
- Add NODE_STARTUP_TIME configuration
* VPCS: 15s base + 2s per additional node
* IOU: 25s base + 3s per additional node
* Other devices: 120s base + 10s per additional node (conservative)
- Add calculate_startup_time() function
* Detects device types via node.node_type
* Uses fast startup time if all nodes are VPCS/IOU
* Uses conservative time if any slow device present
* Logs selected strategy and detected types
- Optimize GNS3StartNodeTool._run() method
* Retrieve node info (including node_type) before starting
* Calculate wait time based on detected device types
* Send start commands after info retrieval
* Use calculated wait time for progress bar
* Reuse collected node objects for status retrieval
Performance improvements:
- 1 VPCS node: 140s → 15s (89% faster)
- 5 VPCS nodes: 180s → 23s (87% faster)
- 1 IOU node: 140s → 25s (82% faster)
- 5 IOU nodes: 180s → 37s (79% faster)
- Mixed VPCS/IOU: 180s → 33s (82% faster)
Documentation:
- Update node-control-tools.md with dynamic wait time strategy
- Add device type comparison table
- Document performance improvements
- Update changelog
Code quality:
- All comments in English
- flake8 check passed
- mypy check passed
Optimize GNS3StartNodeTool with device-type-aware wait time calculation
to significantly reduce startup time for fast devices (VPCS, IOU).
Changes:
- Add NODE_STARTUP_TIME configuration
* VPCS: 10s base + 2s per additional node
* IOU: 20s base + 3s per additional node
* Other devices: 120s base + 10s per additional node (conservative)
- Add calculate_startup_time() function
* Detects device types via node.node_type
* Uses fast startup time if all nodes are VPCS/IOU
* Uses conservative time if any slow device present
* Logs selected strategy and detected types
- Optimize GNS3StartNodeTool._run() method
* Retrieve node info (including node_type) before starting
* Calculate wait time based on detected device types
* Send start commands after info retrieval
* Use calculated wait time for progress bar
* Reuse collected node objects for status retrieval
Performance improvements:
- 1 VPCS node: 140s → 10s (93% faster)
- 5 VPCS nodes: 180s → 18s (90% faster)
- 1 IOU node: 140s → 20s (86% faster)
- 5 IOU nodes: 180s → 32s (82% faster)
- Mixed VPCS/IOU: 180s → 28s (84% faster)
Documentation:
- Update node-control-tools.md with dynamic wait time strategy
- Add device type comparison table
- Document performance improvements
- Update changelog
Code quality:
- All comments in English
- flake8 check passed
- mypy check passed
Security Enhancement:
- API keys are now always filtered to null in all LLM config API responses
- Created LLMModelConfigDataWithoutSecret schema for response validation
- Added _filter_api_key_from_config() helper in API routes
- Modified repository to always hide api_key in get_user_effective_configs()
- Update/create operations still accept and store api_key securely
Documentation Updates:
- Updated API key visibility section to reflect new security policy
- Updated all response examples to show api_key as null
- Marked max_tokens field as reserved for future use
- Added "Reserved Fields" section explaining unused fields
This defense-in-depth approach prevents API keys from being leaked through
logs, browser devtools, or network monitoring.
Add warnings about 'exit' command in three locations to prevent AI from
disconnecting Telnet/SSH sessions during command execution:
- Prompt system rules (lab_automation_assistant_prompt.py)
- Display tool description (display_tools_nornir.py)
- Config tool description (config_tools_nornir.py)
The 'exit' command disconnects the session and causes all subsequent
commands in the batch to fail. This prevents users from viewing
command outputs properly.
- Rename huawei_telnet_ce to gns3_huawei_telnet_ce for consistent naming
- Add comprehensive test suite for RuijieTelnetEnhanced driver (10 tests)
- Update list_netmiko_telnet_devices.py to include gns3_ruijie_telnet
- Fix all flake8 format issues (line length, unused imports, variables)
- Update documentation to reflect device type rename
- Add gns3_ruijie_telnet to supported devices in netmiko_devices.md
- Document custom RuijieTelnetEnhanced driver with hybrid strategy
- Preprocessing: auto-insert 'yes' after known interactive commands
- Fast path: batch send (2-3s for 13 commands)
- Fallback: one-by-one with real-time prompt detection
- Add AAA/password configuration prohibition documentation
- System-level enforcement in lab_automation_assistant_prompt
- Categories: AAA, login passwords, console/VTY auth, encryption
- Document multi-line command handling for banner and similar commands
- Update device_type tag validation with error feedback
- Update multi-vendor support to include Ruijie platform
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add pre-processing of known interactive commands and implement hybrid send strategy for Ruijie Telnet devices. The new approach:
- Pre-processes configuration commands to automatically insert 'yes' responses after known interactive commands (router-id, erase, delete, format, reload, boot system)
- Implements hybrid strategy: first attempts fast batch send with pre-processed commands, then falls back to one-by-one send with real-time prompt detection if batch fails
- Maintains backward compatibility while improving reliability for interactive configuration scenarios
This improves configuration reliability for Ruijie devices that frequently require confirmation prompts during configuration changes.
- Import and register Ruijie telnet device type in config_tools_nornir.py
- Import and register Ruijie telnet device type in display_tools_nornir.py
- Update custom_netmiko __init__.py to include RuijieTelnetEnhanced driver
- Add Ruijie telnet driver to __all__ exports for proper module exposure
- Extends custom Netmiko support to handle Ruijie devices with interactive prompt handling
- Add explicit AAA/password configuration prohibition to safety reminders
- Implement multiline command expansion for banner and similar commands
- Add error handling for devices with missing device_type tags
- Improve logging for configuration errors and multiline expansions
practice for multi-vendor device support
Refactor Nornir configuration to use host-level connection_options
instead of dynamic groups, following Nornir's configuration priority
model (host > group > defaults).
**Problem:**
Previous implementation used first device's configuration for all
devices, causing Cisco devices to use Huawei driver and vice versa.
**Solution:**
- Each host now has device-specific connection_options at host level
- Single generic "network_devices" group for shared settings
- Host-level config automatically overrides group-level config
**Changes:**
- Remove: _get_nornir_groups_config() helper function
- Remove: _get_nornir_group() helper function
- Simplify: _initialize_nornir() to use single generic group
- Update: get_gns3_device_port.py() to return host-level config
- Reserve: platform field for future NAPALM/scrapli plugin support
**Benefits:**
- Cleaner code structure (no dynamic group creation)
- Follows Nornir best practice ("configuration proximity")
- Easy to extend with new device types
- Properly handles mixed-vendor topologies
Netmiko's `ssh_dispatcher` calculates platform lists at module import
time. When custom device types (like Huawei CE) are registered
dynamically, these cached lists become stale and do not include the
new platforms.
This change imports `netmiko.ssh_dispatcher` and recalculates the
`platforms`, `platforms_base`, and `telnet_platforms` attributes to
ensure Netmiko recognizes the custom device types.
- Add script to generate Markdown documentation of all Netmiko supported
devices (SSH and Telnet), grouped by platform with source attribution
- Highlight custom GNS3-Copilot devices with "Custom ✨" marker
- Auto-generate device list to docs/gns3-copilot/netmiko_devices.md
- Simplify HuaweiTelnetCE driver: remove redundant aliases
(huawei_ce, huawei_telnet_ce_telnet), keep only huawei_telnet_ce
- Update tests to match simplified device registration
Disable mypy type checking for the Huawei CE driver module due to
Netmiko library limitations. Netmiko lacks type stubs (py.typed) and
uses dynamic attributes, which causes unresolved import and attribute
errors in static analysis.
Added a comprehensive comment block at the top of the file explaining
the rationale for disabling mypy to prevent future confusion.
Additionally, performed code cleanup including:
- Reformatted module docstrings and comments for better readability
- Added missing imports (importlib, logging)
- Removed unused typing imports (Optional)
- Refactored variable assignments in send_config_set for clarity
Add comprehensive multi-vendor support for GNS3 network automation,
including a custom Netmiko driver for Huawei CloudEngine devices.
Features:
- Custom HuaweiTelnetCE driver for GNS3 emulation (no authentication)
- Auto-commit before exit to prevent [Y/N/C] prompts
- Dynamic device type detection from GNS3 node tags
- Support for both Cisco IOS and Huawei devices
- Proper VRP command handling (system-view, return confirmation)
Implementation:
- New package: utils/custom_netmiko/
- huawei_ce.py: Huawei CloudEngine driver
- tests/test_huawei_ce.py: Unit tests (9/9 passing)
- README.md: Driver development guide
- Updated tools for multi-vendor support:
- display_tools_nornir.py: Dynamic group generation
- config_tools_nornir.py: Multi-vendor config commands
- get_gns3_device_port.py: Device port extraction
- Documentation: multi-vendor-device-support.md
Limitations:
- huawei_telnet_ce driver requires devices without authentication
- For devices with username/password, use standard huawei_telnet driver
Co-Authored-By: Yue Guobin <yueguobin@outlook.com>"
Simplify the documentation structure in `README.md` by removing the
`todo/` directory reference and detailed design documents for planned
features. Consolidate future roadmap items into a high-level summary
under "Future Enhancements".
Update `node-control-tools.md` to include documentation for new topology
management tools (create node, create link, get template, rename node)
and reflect updated API imports for `Link` support.
Fix the path mismatch between /acl/endpoints API and actual routes:
- Users: /users/{id} → /access/users/{id}
- Groups: /groups/{id} → /access/groups/{id}
- Roles: /roles/{id} → /access/roles/{id}
This fixes the error where creating ACE entries fails with:
"Path '/groups/{id}' doesn't match any existing endpoint"
The actual routes are registered under /access/ prefix, but the
endpoints API was returning paths without the prefix.
Co-Authored-By: Yue Guobin <yueguobin@outlook.com>
- Upgrade langchain packages to latest versions (langchain 1.2.10, langgraph 1.0.9, etc.)
- Add langsmith SDK for enhanced observability and tracing
- Update Pillow to 12.1.1 for image processing improvements
- Maintain compatibility with existing AI and automation framework
Add comprehensive documentation proposing TOSCA (Topology and Orchestration Specification for Cloud Applications) as the standard format for GNS3 network topologies. The document outlines strategic benefits including standardized YAML descriptions, toolchain ecosystem integration, Git-based workflows, and template reuse capabilities. This initiative aims to modernize GNS3 topology management, improve user experience, and align with industry best practices for network automation and orchestration.
Fixed IOU node suspend API to return proper HTTP 405 Method Not Allowed
error instead of misleading 204 No Content response.
Changes:
- Added HTTPException import to iou_nodes.py
- Fixed suspend_iou_node route from /stop to /suspend (bug fix)
- Changed response from 204 No Content to 405 Method Not Allowed
- Added clear error message: "Suspend is not supported for IOU nodes"
This fix ensures clients receive explicit feedback when attempting to
suspend IOU nodes, which do not support suspend functionality.
Related issue: IOU nodes previously returned 404 when suspend was called
due to incorrect route registration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Add GNS3StopNodeTool and GNS3SuspendNodeTool to lab automation assistant mode
- Update tools_v2 __init__.py to export new node control tools
- Document node control tools in README with key features and implementation status
- Update last modified date in documentation
The new tools provide complete node lifecycle control for automated lab workflows, including stopping nodes for shutdown and suspending nodes while preserving state.
- Remove redundant "(REQUIRED)" and detailed explanations from context_limit field descriptions
- Shorten copilot_mode descriptions by removing parenthetical details about mode capabilities
- Maintain field formatting consistency across LLMModelConfigData, Create, and Update schemas
- Add README.md with documentation overview and structure guide
- Move implemented designs to docs/gns3-copilot/implemented/:
- chat-api.md (from ai-chat-api-design.md)
- llm-model-configs.md (from llm-model-configs-api.md)
- command-security.md
- context-window-management.md
- Add Jinja2 configuration template system design documents:
- jinja2-config-templates-system.md
- config-templates-implementation-guide.md
- ai-prompting-for-config-templates.md
- Remove obsolete documents (acl-web-ui, Chinese RBAC doc)
This reorganization makes it clearer which features are implemented
vs planned, following the established documentation structure.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive documentation for AI prompting to generate structured configuration data for Jinja2 templates. The guide includes:
- Core system prompt with critical rules for structured data generation
- Supported vendors and OS types (Cisco, Juniper, Huawei, Arista, Mikrotik)
- Detailed schemas for network features including OSPF, BGP, VLANs, ACLs, and more
- Example prompts and expected structured outputs
- Integration with the configuration renderer system
This documentation ensures AI-generated configurations follow the required structured format for proper template rendering, preventing direct configuration text generation and maintaining consistency across different network device vendors.
- Add exception for .claude/development.md to allow tracking development documentation
- Comment out PROJECT_CONTEXT.md exclusion to enable version control of project context file
- Create PROJECT_CONTEXT.md with comprehensive project overview for AI assistant support
- Document project structure, AI copilot data flow, SSE event types, and code standards
- Provide flake8 static analysis guidelines and common error fixes
Added new section in ai-chat-api-design.md explaining:
- LangGraph Agent architecture and main components
- tool_node function and tool output serialization mechanism
- Why serialization happens in tool_node (not agent_service)
- Tool output data flow diagram showing SSE and history paths
- Explanation of JSON format consistency across streaming and storage
This documentation clarifies the fix for single-quotes issue in
conversation history and helps future maintenance.
Co-Authored-By: YueGuobin <yueguobin@outlook.com>
Fixed tool output serialization in tool_node function to ensure
ToolMessage.content is always in JSON format, not Python str() representation.
This fixes the issue where conversation history showed tool outputs
with single quotes (Python format) instead of standard JSON.
Changes:
- Added json import to gns3_copilot.py
- Modified tool_node() to serialize observation to JSON before creating ToolMessage
- Ensures both SSE streaming and history storage use consistent JSON format
Root cause: ToolMessage was created with raw dict/list objects, which
LangChain converted to Python str() representation when saving to history.
Co-Authored-By: YueGuobin <yueguobin@outlook.com>
Add PROJECT_CONTEXT.md to the .gitignore file to prevent it from being tracked in version control. This file likely contains project-specific context or configuration that should not be committed to the repository.
Changed tool output serialization in AgentService._convert_event_to_chunk()
from str() to json.dumps() to ensure structured data (dict/list) is properly
formatted as standard JSON instead of Python string representation.
Changes:
- Added json import to agent_service.py
- Modified on_tool_end event handling to use json.dumps(output, ensure_ascii=False, indent=2)
- Updated ai-chat-api-design.md to document tool_output format
Benefits:
- Frontend can parse tool results with standard JSON.parse()
- Chinese and non-ASCII characters are preserved (not escaped)
- Formatted output (indent=2) improves readability
Co-Authored-By: YueGuobin <yueguobin@outlook.com>
Updated the author name and copyright statements across the
gns3_copilot module. The name has been standardized from
"Guobin Yue" to "Yue Guobin (岳国宾)" to reflect the correct
author attribution including Chinese characters.
- Improve POST /chat endpoint documentation with request/response examples
- Add session ID management flow explanation
- Enhance GET /sessions endpoint with query parameters and response example
- Update GET /sessions/{session_id}/history with detailed response structure
- Format parameters as tables for better readability
- Clarify session ID usage in streaming conversations
Add .claude/ directory to .gitignore to prevent accidental
commit of Claude Code settings which may contain sensitive
API keys. This ensures development environment configuration
files with potential credentials are excluded from version
control.
Add comprehensive documentation for handling datetime timezone discrepancies between backend and frontend. The issue arises when backend returns naive datetime strings without timezone suffixes, causing JavaScript to parse them as local time instead of UTC. The guide includes problem description, root cause analysis, three frontend solutions (dayjs UTC parsing, manual 'Z' suffix addition, and global Axios interceptor), backend context, and testing checklist.
Add comprehensive implementation guide for ACL management feature in GNS3 Web UI. The guide includes:
- Feature overview with core functionality and user flow
- Detailed API endpoint specifications for ACE CRUD operations
- Data structures and relationships
- Frontend implementation guide with component architecture
- UI/UX design recommendations and wireframes
- Common usage scenarios and error handling patterns
- Example code with React components and API service layer
This document serves as a reference for frontend developers implementing ACL management interface, covering everything from API integration to user interface design.
Add comprehensive documentation for the two-tier permission control system combining RBAC and ACL features. The guide covers system overview, core concepts, data model, permission check flow, usage examples, best practices, and common issues. This documentation is applicable for GNS3 Server v3.0+ and provides implementation details for administrators managing user permissions.
Add detailed section explaining that plaintext API keys for group configurations are never exposed through the application API, even to super admins. This clarifies the security design where group configs are intended for inheritance only, not manual viewing, while maintaining internal decryption for inheritance functionality.
Update the LLM model configs API documentation to provide clearer explanations of API key visibility controls and encryption behavior. The changes include:
- Enhanced visibility table with more specific scenarios and encryption states
- Added detailed rules explaining when API keys are visible as plaintext, hidden (null), or shown encrypted
- Clarified super admin capabilities and database-level access
- Updated JSON examples to reflect actual encrypted values and null placeholders
- Added important notes about Fernet encryption, on-the-fly decryption, and group config behavior
These updates provide better transparency about security measures and help users understand what to expect when viewing different types of configurations.
Add comprehensive user context to the `/me` endpoint by including group memberships, accessible resource pools, and access control entries (ACEs). This enables users to view inherited configurations, available resources, and their permissions directly from the API.
Key additions:
- Group membership details with inherited configs
- Resource pool access information
- ACE visibility for permission transparency
- Support for user-selectable group default configurations
The enhancement addresses user needs for better visibility into permissions and accessible resources within the system.
Changed the example value of `copilot_mode` from "lab_assistant" to "lab_automation_assistant" in the API documentation to reflect the correct mode name used in the system.
Rename base_prompt.py to teaching_assistant_prompt.py and lab_assistant_prompt.py to lab_automation_assistant_prompt.py to better reflect their purposes. Update all imports and references accordingly to maintain consistency across the codebase. This improves code readability and aligns naming with the actual functionality of each prompt module.
The `python scripts/show_model_context_limits.py` command was removed from the documentation as it is no longer necessary or relevant for users configuring model context limits. The remaining content still provides clear guidance on calculating context limits in K tokens.
Translate the GNS3 Copilot Agent Chat API design document from Chinese to English to improve accessibility for international contributors and align with project documentation standards. The translation covers all sections including overview, core features, architecture design, API endpoints, and response formats.
Add comprehensive design document outlining the race condition issue when multiple users simultaneously operate on the same network device via GNS3-Copilot Agent. The document details the problem statement, affected components, and proposes two solutions: device-level mutex lock (recommended) and connection pooling with session isolation. It includes implementation details, API changes, and UI considerations to ensure safe concurrent operations.
Add support for runtime control parameters `max_iterations` and `max_tool_calls` in the chat API to allow users to dynamically adjust agent behavior per request. This addresses current limitations where iteration limits and tool call constraints are hardcoded, providing flexibility for complex tasks and cost control.
- Import filter_forbidden_commands utility from command_filter module
- Add _filter_forbidden_commands_from_device_configs method to filter out restricted commands before execution
- Store blocked commands information and log filtered commands for audit purposes
- Update _process_task_results to include blocked commands info in response
- Prevent execution of potentially dangerous commands while maintaining transparency about filtered content
Add comprehensive documentation for troubleshooting issues caused by using `kill -9` on gns3server processes. The guide explains the root cause where SIGKILL prevents proper cleanup of child processes like dynamips and vpcs, leading to port conflicts and resource allocation errors when restarting. It provides multiple solutions including manual process cleanup, proper shutdown procedures, and preventive measures with example scripts. This documentation helps users resolve common issues with Dynamips VM creation failures, undefined project_id errors, and TCP port warnings.
Updated references to the title generation node in both documentation and code:
- Changed node name from `generate_title` to `title_generator_node` in API design documentation
- Updated filtering logic in agent service to exclude `title_generator_node` from LLM call statistics, token counting, and frontend streaming events
- Maintains same functionality while using more descriptive node name for clarity
- Move command-security.md and hitl-implementation-plan.md to todo/ directory
- Add new documentation for orphan tool calls recovery with detailed problem analysis and implementation plan
- Document scenarios causing orphan tool calls and propose fix strategy using LangGraph API
Filter out internal LangGraph 'generate_title' node from LLM call counting and token usage tracking to avoid inflating statistics with internal operations. This ensures metrics only reflect user-facing AI interactions.
- Update API documentation to reflect new streaming tool call mechanism
- Add `message_id` optional field to content and tool_call events
- Change tool_call structure from array to single object with incremental updates
- Add `tool_call_id` to tool_start events for better event correlation
- Implement ToolCallStreamAccumulator class to handle parameter accumulation
- Provide frontend example code for handling streaming tool calls
- Maintain backward compatibility with existing session_id tracking
- Update AI chat API documentation with revised SSE event schema
- Add support for multiple tool calls in `tool_call` events
- Include `session_id` in all event types for better session tracking
- Implement `on_chat_model_end` handler to process LLM tool call decisions
- Update example JSON payloads to reflect new schema structure
- Rename "teaching" mode to "teaching_assistant" for better clarity
- Rename "lab_assistant" mode to "lab_automation_assistant" to reflect expanded capabilities
- Implement mode-specific tool sets: teaching_assistant gets read-only diagnostic tools only, while lab_automation_assistant gets full diagnostic and configuration tools
- Update API documentation examples to reflect new mode names
- Maintain backward compatibility with default tool set initialization
Set logging level for nornir.core and nornir loggers to WARNING in config_tools_nornir.py and display_tools_nornir.py. This prevents nornir from logging task execution at INFO level to the console, as the logging={"enabled": False} parameter in InitNornir only disables plugin internal logs.
- Added `temperature` parameter to Chat API documentation with implementation notes
- Improved code formatting in context_manager.py with consistent string quotes and line breaks
- Added section on future runtime LLM parameter override capabilities
- Updated API schemas to include temperature parameter (currently unused but reserved for future implementation)
- Extract context variable management functions from connector_factory.py to new context_helpers.py module
- Update imports in gns3_copilot.py, agent_service.py, and __init__.py to use new module
- Remove inline imports and ensure consistent access to context helpers
- Improves code organization and maintainability by separating concerns
- Add `copilot_mode` field to request examples in API documentation
- Update prompt loader to read `copilot_mode` from flattened config structure
- Support both "teaching" and "lab_assistant" modes for different assistant behaviors
- Add `copilot_mode` field to LLM model configs API with "teaching" (diagnostics only) and "lab_assistant" (full configuration access) modes
- Introduce new `ExecuteMultipleDeviceConfigCommands` tool for executing configuration commands on multiple devices
- Include `tags` field in node data structure for enhanced project management
- Update API documentation examples to reflect new `copilot_mode` field and context limit additions
Removed extensive implementation details and configuration examples from the context window management documentation. The document now focuses on core permissions and prohibitions for tool usage, providing a clearer and more concise reference for allowed and forbidden actions. This streamlines the documentation to essential guidelines only.
Add copyright notice and author attribution to multiple Python files in the gns3-copilot module. This ensures proper licensing attribution and clarifies authorship for the project files.
Removed repetitive "This module is part of the GNS3-Copilot project" and GitHub URL comments from multiple module docstrings. These comments were redundant since the project information is already established in the main package documentation. This cleanup improves code readability and reduces maintenance overhead by eliminating duplicate attribution statements across the codebase.
- Refactor system message structure to combine system prompt and topology info using template variables
- Update token calculation process with merged system message approach
- Clarify priority order for message retention during context window management
- Add detailed token counting implementation using tiktoken library
- Include boundary case handling for system message exceeding budget
- Add SPDX license headers to tool files for proper licensing documentation
Refactor context preparation to embed topology information directly into the system prompt using a {{topology_info}} placeholder, replacing the previous approach of appending a separate SystemMessage. This consolidates context into a single system message and simplifies token accounting. The logging is updated to reflect the new token breakdown, showing combined system prompt tokens (base + topology) instead of separate components.
The GNS3TopologyTool has been removed from the list of available tools for the agent. This change simplifies the toolset by eliminating a tool that is no longer needed or supported in the current workflow.
Enhanced the context window management system to properly account for tool definition tokens when trimming messages. The key changes include:
- Updated `trim_messages_for_context` function to accept `tool_tokens` parameter
- Modified token budget allocation logic to subtract tool tokens before message trimming
- Added detailed documentation explaining the token budget distribution between messages and tool definitions
- Implemented prioritized trimming strategy that preserves system messages and recent conversation history
- Added boundary case handling for scenarios where system messages or tools exceed available budget
The improvements ensure more accurate context window management by accounting for the ~1000-2000 tokens typically consumed by tool definitions that LangChain automatically includes in LLM requests.
- Add tiktoken as a required dependency for accurate token counting
- Update documentation with installation instructions and token counting strategy
- Improve logging to include tool definition token estimates
- Enhance error handling to fail fast when tiktoken is not available
- Update context manager to use tiktoken's cl100k_base encoding for GPT-4 compatibility
- Add `context_limit` as required field for LLM model configurations
- Add `context_strategy` as optional field with three trimming strategies
- Update API documentation with detailed examples for GPT-4o and Claude 3.5 Sonnet
- Clarify that context limit is specified in K tokens (thousands of tokens)
- Update example payloads to reflect current model versions and new fields
- Move AI chat API design document to gns3-copilot directory
- Add comprehensive HITL implementation plan with architecture and workflow
- Introduce human-in-the-loop confirmation for dangerous configuration commands
- Include state management, API endpoints, and frontend integration details
- Provide testing plan and deployment steps for the new feature
Add `normalize_tool_response` function to standardize tool output formats for consistent frontend display. The function converts various response types (dict, list, string) into a unified structure with success metrics, detailed data arrays, and metadata. This ensures backward compatibility while providing predictable response formats for UI components.
- Remove unused `llm_calls` variable and redundant logging in `should_continue`
- Simplify title generation routing by eliminating unnecessary condition checks
- Improve code clarity and maintainability by focusing on essential flow control
- Add `pinned` column to chat_sessions table with default FALSE
- Implement database migration for existing installations using PRAGMA table_info
- Create composite index for pinned + updated_at sorting
- Add pin/unpin API endpoints (PUT/DELETE /sessions/{id}/pin)
- Update session listing to sort by pinned status then updated_at
- Extend ChatSessionsRepository with pin_session method
- Update API documentation to reflect new pinning functionality
The feature allows users to pin important chat sessions to the top of the list. Sessions are sorted with pinned sessions first (by updated_at), followed by regular sessions (by updated_at). Database migration ensures backward compatibility with existing installations.
- Add message ID generation for initial HumanMessage creation
- Implement message converters for LangChain/OpenAI format interoperability
- Update documentation with detailed message format specifications
- Refactor AgentService to use centralized message conversion utilities
- Ensure tool_calls format compliance with OpenAI API standards
Update the AI chat API design documentation to provide comprehensive details about statistics collection during streaming conversations. The documentation now includes:
1. **Enhanced statistics collection logic**:
- Clarified message_count increments for user messages, AI responses, and tool results
- Added LLM call tracking via on_chat_model_start events
- Detailed token counting methodology using LangGraph's usage_metadata
2. **Improved implementation details**:
- Added specific event handlers for statistics collection
- Explained LangGraph's cumulative token counting behavior
- Provided real-world examples of token accumulation
3. **Updated data models**:
- Enhanced ChatSession model documentation with field descriptions
- Separated fields into categories (basic, statistics, timestamps, reserved)
4. **Refined architecture documentation**:
- Added detailed flow for stream_chat method
- Documented statistics collection mechanism during SSE streaming
- Explained batch update strategy to reduce database writes
The changes ensure developers understand how conversation statistics are collected, processed, and stored without impacting streaming performance.
Add initialization check for `_checkpointer_conn` in `AgentService` to ensure the checkpointer database connection exists before attempting to retrieve chat sessions. This prevents potential null reference errors when the checkpointer hasn't been initialized yet during agent operations.
Introduce a new tool for updating node names within the GNS3 copilot agent. This expands the agent's capabilities to include node name modifications alongside existing node and link management operations.
Improve logging in GNS3 topology reader to provide more structured and informative output. The previous single-line JSON log has been replaced with separate info and debug logs:
- Info log now includes project ID, project name, node count, and link count
- Debug log retains the full topology details for deeper inspection
This makes it easier to monitor topology retrieval in production while keeping detailed data available for debugging.
- Remove `selected_project` tuple from MessagesState as it's no longer needed
- Replace tuple-based project selection with direct `project_id` from config
- Remove unused `mode` parameter from llm_call function
- Update topology retrieval to use project_id directly from configurable settings
- Streamline context messages by removing redundant project info formatting
- Move project_id from metadata to configurable section in agent_service config
Add GNS3ProjectInfoTool to the __all__ list in gns3_client/__init__.py to make it available for import. This ensures the tool is properly exposed as part of the public API for use in copilot agent modules.
- Add info and debug logging to llm_call node for tracking LLM invocations and configuration
- Add error handling and logging to tool_node for tool execution failures
- Add startup logging to stream_chat method with session details
- Improve observability of agent workflow and debugging capabilities
The `get_gns3_connector` function now accepts an optional `jwt_token` parameter. If not provided, the token will be retrieved from context, improving flexibility for scenarios where authentication is handled externally or deferred.
The `stream_chat` method was yielding a "done" message after streaming all chunks, but this is unnecessary as the streaming completion is already indicated by the end of the stream. Removing this redundant message simplifies the response handling and aligns with typical streaming patterns.
Add project status validation to all chat API endpoints to ensure the project is opened before allowing chat operations. This prevents unauthorized access and ensures chat functionality only works with active projects.
- Check project.status == "opened" in stream_chat, list_sessions, get_history, and delete_session endpoints
- Return HTTP 403 FORBIDDEN with descriptive error message if project is not opened
- Update docstring for stream_chat endpoint to document the requirement
- Refactor `llm_call` and `generate_title` nodes to retrieve `llm_config` from request-scoped context variable instead of LangGraph config
- Remove `jwt_token` and `llm_config` from LangGraph configurable parameters in `AgentService.stream`
- Add `set_current_llm_config` and `get_current_llm_config` functions to `connector_factory` and export them in `__init__.py`
- Update `tool_node` to no longer extract `jwt_token` from config as it is now handled via context variable
- Improves thread safety and decouples configuration from LangGraph's state management
- Move JWT token from state to configurable context for better security and request isolation
- Add user_id parameter to agent service for enhanced metadata tracking
- Update checkpoint directory name from .gns3-copilot to gns3-copilot
- Implement context-aware JWT token management using ContextVar
- Improve tool node to extract JWT token from config instead of state
Update agent service to properly access content from AIMessageChunk objects during chat model streaming. Instead of using dictionary get method on the chunk, now use getattr to directly access the content attribute, ensuring compatibility with the AIMessageChunk object structure.
- Replace separate user_id and jwt_token parameters with unified llm_config dict
- Simplify model factory to accept llm_config directly instead of fetching from API
- Update llm_call and generate_title nodes to extract llm_config from LangGraph config
- Remove deprecated API fetching logic from model factory
- Maintain backward compatibility for existing tool usage patterns
This change centralizes LLM configuration management, reducing API calls and improving performance by passing configuration directly from the API layer rather than fetching it repeatedly.
Refactor get_llm_config to handle various async contexts more robustly. The function now properly checks for running event loops using asyncio.get_running_loop() and handles edge cases when called from thread pools or existing loops. This prevents RuntimeErrors and ensures reliable execution in both sync and async environments.
Remove support for environment variable fallback in LLM model configuration. The configuration now strictly follows:
1. Provided llm_config dictionary (highest priority)
2. Fetch from llm_model_configs system via connector_factory (requires user_id and jwt_token)
This change ensures consistent configuration management and eliminates the outdated environment variable approach. When no configuration is found, a clear ValueError is raised with appropriate error messages.
- Change chat router prefix from `/chat` to `/projects/{project_id}/chat`
- Add `dep_project` dependency to inject Project instance into endpoints
- Remove manual project validation in `stream_chat` and use dependency instead
- Add placeholder `list_sessions` endpoint for future session listing
- Update `get_history` endpoint to use project dependency and adjust path
- Improve code organization and error handling for project retrieval
Add explicit Query parameter with description to the `list_sessions` endpoint for better API documentation and clarity. The `project_id` parameter now includes a descriptive label indicating it is a GNS3 project ID.
- Change config parameter type from dict to RunnableConfig | None in llm_call and generate_title functions
- This improves type safety and aligns with LangChain's RunnableConfig usage
- No functional changes, only type annotations updated for better integration
Updated import statements across multiple agent files to use absolute paths starting with `gns3server.agent.gns3_copilot` instead of relative `gns3_copilot` imports. This ensures proper module resolution within the gns3-server package structure and prevents import errors when the agent is executed from different contexts.
- Modified `llm_call` and `generate_title` functions to accept `config` parameter, extracting `user_id` and `jwt_token` for per-user LLM configuration and API authentication
- Updated `create_base_model_with_tools` and `create_title_model` calls to pass user authentication details
- Added `jwt_token` to state for tool usage in GNS3 API calls
- Integrated chat router into controller API routes under `/chat` endpoint
- Implemented `_cleanup_copilot_agent` method in `Project` class to remove AgentService resources upon project closure, preventing resource leaks
- Enhanced error handling in agent cleanup to avoid interrupting project close operations
This commit introduces a comprehensive design document outlining the implementation of AI Chat API for GNS3 Copilot Agent within GNS3 Server. The document provides:
- Overview and background on existing components including GNS3 Copilot Agent, LLM configuration management, and API framework
- Reference implementation details from FlowNet-Lab project
- Architecture design with clear component interactions between frontend clients and backend services
- RESTful API specifications for chat streaming, session management, and history retrieval
- Implementation details covering project-based agent management, SQLite checkpoint storage, and LangGraph integration
- Security considerations and deployment guidelines
The design enables clients to interact with GNS3 Copilot Agent through standardized APIs, supporting real-time chat streaming and persistent conversation sessions per project.
Removed GNS3UpdateDrawingTool import and from __all__ list in gns3_client __init__.py to clean up the public interface and eliminate unused or deprecated components.
Update all references from FlowNet-Lab to GNS3-Copilot in package names, documentation, and logging. This includes:
- Module and package __init__.py files
- License headers and file descriptions
- Log messages and internal comments
- Remove deprecated tools: GNS3CreateAreaDrawingTool and LinuxTelnetBatchTool
The renaming aligns with the project's new branding while maintaining all existing functionality.
Add comprehensive dependencies for the new GNS3 Copilot AI agent feature. This includes:
- Core AI and automation frameworks (LangChain, LangGraph)
- Multiple model provider integrations (OpenAI, Anthropic, Google, AWS, Ollama, DeepSeek, xAI)
- Network automation tools (Netmiko, Nornir)
- Supporting libraries for telnet, HTTP requests, authentication, and image processing
The dependencies are organized into a dedicated section with clear comments for maintainability.
Refactor model factory to support three configuration sources in priority order:
1. Direct llm_config dictionary parameter
2. Fetch from llm_model_configs system via connector_factory (requires user_id and jwt_token)
3. Environment variables as fallback for backward compatibility
This improves flexibility by allowing runtime configuration while maintaining compatibility with existing environment-based setups.
Removed checkpoint-related imports and exports from the agent package's __init__.py to clean up the public API. This change reduces unnecessary exposure of internal checkpoint utility functions, focusing the public interface on the core agent_builder functionality.
- Add `get_gns3_server_host()` function to `connector_factory.py` for extracting GNS3 server hostname from controller, config, or default URL
- Export new function in `__init__.py` for public API access
- Replace `os.getenv("GNS3_SERVER_HOST", "127.0.0.1")` calls with `get_gns3_server_host()` in Nornir configuration tools (`config_tools_nornir.py`, `display_tools_nornir.py`)
- Ensures consistent host detection across tools using the same priority logic as `get_gns3_connector`
Removed GNS3_SERVER_USERNAME and GNS3_SERVER_PASSWORD environment variables from Nornir configuration tools. Credentials are now set to empty strings by default, simplifying configuration and removing dependency on environment variables for authentication.
- Rename module description from FlowNet-Lab to GNS3 Copilot
- Replace linux_specialist_prompt and experiment_deploy_prompt imports with base_prompt
- Update __all__ export list to include SYSTEM_PROMPT instead of removed prompts
- Improve module docstring with detailed component descriptions and available prompts
- Maintain dynamic version management and module metadata
- Remove direct logging of LLM config from gns3_copilot.py
- Update model_factory to accept configuration from llm_model_configs dictionary
- Add fallback to environment variables for backward compatibility
- Centralize configuration loading in _load_llm_config function
Introduce `get_gns3_connector_with_llm_config` as a convenience function that combines the creation of a GNS3 API connector and retrieval of the user's default LLM configuration. This simplifies initialization for operations requiring both GNS3 connectivity and AI model settings, reducing boilerplate code in callers. The function returns a dictionary containing the connector and LLM config, or None on failure.
Integrate the gns3-copilot AI assistant module to provide intelligent
automation and interaction capabilities for GNS3 network emulation.
Key components:
- AI agent framework with LLM integration (supports Qwen vision model)
- GNS3 client library for project topology management
- Extensive prompt templates for various network operation scenarios
- Tool library for node creation, linking, configuration, and management
- Support for English level assessment (A1-C2) and specialized personas
- Network drawing and topology visualization tools
- Linux device automation via Nornir/Telnetlib
- Window controller for UI interaction
Features:
- Multi-modal AI agent with vision capabilities
- Automated network topology deployment and configuration
- Interactive node and drawing management
- File-based project operations (read, write, list)
- Specialized prompts for different scenarios and skill levels
- Comprehensive tool set for network device management
Updated documentation and implementation to clearly define the priority order for selecting default LLM model configurations. The logic now explicitly states:
1. User's config marked with `is_default: true` (highest priority)
2. Group's config marked with `is_default: true`
3. First config in the list (user configs come before group configs)
This ensures consistent behavior between the API documentation and the actual implementation in the repository code.
Update API documentation to reflect new nested `config` object structure in LLM model configurations endpoints. The response format now encapsulates provider-specific fields (provider, base_url, model, temperature, api_key, max_tokens) within a `config` object, while moving ownership metadata (user_id, group_id, is_default, version, created_at, updated_at) to the top level. This aligns the user-facing endpoints with the group configuration structure and improves API consistency.
- Add note clarifying that GET endpoints for groups return the same structure as user endpoints
- Document LLMModelConfigListResponse schema with default configuration selection logic
- Add comprehensive example for GET group configurations endpoint
- Update endpoint numbering to accommodate new group endpoints
- Ensure consistency between user and group API documentation
- Update API documentation to explicitly describe default configuration selection logic
- Add fallback behavior in repository to use first config when no default is marked
- Clarify difference between `/default` endpoint and `default_config` field
- Document that `default_config` is never null when configs list is not empty
- Add `/default` endpoints for users and groups to retrieve default LLM model configurations
- Update documentation to clarify that users receive both own and inherited configurations
- Improve response examples to show combined configs with source field
- Add 404 response example for missing default configurations
- Fix optimistic locking documentation formatting
Add explicit datetime.utcnow() assignments for created_at and updated_at fields in LLMModelConfigsRepository to ensure proper timestamp handling with SQLite. This addresses issues where SQLite may not automatically populate these timestamp fields during create and update operations. Changes applied to both user and group configuration methods for consistency.
When no configuration file is found or readable, the server now still loads secret files. This ensures that secret configurations (like API keys or passwords) are available even if the primary config file is missing, improving robustness and security in environments where secrets are stored separately.
- Change `JSONB` columns to generic `JSON` in LLMModelConfig model for database compatibility
- Update migration to use `sa.String(32)` for UUID and `sa.JSON()` for config fields
- Remove PostgreSQL dialect imports to support multiple database backends
- Keep existing constraints and indexes with PostgreSQL-specific annotations where needed
The migration file `20260303_create_llm_model_configs_table.py` had an incorrect `down_revision` reference. Changed from `7ceeddd9c9a8` to `98083573d011` to properly link to the previous migration in the Alembic history. This ensures the migration chain is consistent and rollbacks work as expected.
Replace deferred UniqueConstraints with partial unique indexes for user and group default configurations in the LLM model configs table. This change improves performance and ensures at most one default config per user/group while maintaining data integrity. The migration script has been updated accordingly to create and drop the new indexes.
- Add `model_type` field to database schema with supported values (text, vision, stt, tts, multimodal, embedding, reranking, other)
- Add `name` field as table-level column for indexing and filtering
- Add reserved JSONB fields for future extensibility
- Update API request/response schemas to include `model_type` and `name` fields
- Add new `LLMModelConfigWithSource` schema for detailed configuration responses
- Update usage examples to reflect new required fields
- Improve database constraints and indexing documentation
Add comprehensive documentation for optimistic locking implementation in the LLM model configurations API. The update includes:
- Added "Optimistic Locking" feature to the overview section
- Added `version` field to the database schema table
- Updated `LLMModelConfigUpdate` schema to include `expected_version` parameter
- Updated `LLMModelConfigResponse` schema to include `version` field
- Added detailed examples for update operations with optimistic locking
- Included conflict handling workflow and client retry instructions
This documentation ensures users understand how to prevent concurrent modification conflicts when updating LLM model configurations.
- Include `version` field in all LLM model config response schemas
- Add `expected_version` parameter to update endpoints for optimistic locking
- Handle concurrent modification errors with HTTP 409 Conflict status
- Update both user and group config endpoints consistently
Add a new method `_load_encryption_key` to initialize encryption for sensitive data such as API keys. This method is called within `_load_secret_files` alongside JWT secret key loading, ensuring encryption is set up during server configuration. The change enhances security by enabling encryption for secrets stored in the server's secrets directory.
- Add smarter database state detection during initialization to handle new databases, existing databases with new features, and old databases needing migration
- Make migration for llm_model_configs table idempotent to prevent conflicts when table already exists from code
- Add detailed logging for different database initialization scenarios
- Import sqlalchemy module for database inspection capabilities
- Introduce new API route `/access` for managing LLM model configurations
- Add LLMModelConfig model to database models
- Include comprehensive schemas for LLM model config CRUD operations
- Register new router with tags for LLM Model Configurations
When a Docker container with the same name already exists (e.g., from a
previous crashed GNS3 session), Docker returns a 409 Conflict error
when trying to create a new container with that name. This causes the
project open operation to fail.
This fix adds automatic cleanup of stale containers when encountering
a name conflict:
- Added DockerHttp409Error exception class
- Updated http_query to detect 409 status codes
- Modified create() to remove conflicting containers and retry
Fixes the issue where opening a project fails with:
"Docker has returned an error: 409 Conflict. The container name
'/GNS3.xxx' is already in use by container 'xxx'"
Add an additional fallback check for the VBoxManage executable using the capitalized "VBoxManage" command name. This improves compatibility on systems where the executable may be case-sensitive or installed with a different naming convention, ensuring the VirtualBox manager can locate the necessary binary when the lowercase "vboxmanage" is not found.
Refactor port name assignment to use `or` operator for fallback values, improving code readability and consistency. Changes applied in `node.py` and `port_factory.py` to handle custom adapter settings more cleanly.
Add conditional checks to ensure `self._name` is not None before performing string operations in the `short_name` property. This prevents potential AttributeError exceptions when port name is undefined, improving robustness and compatibility with edge cases in port configuration.
Use dict.get() method to safely access 'image' and 'path' keys in settings dictionary to avoid KeyError exceptions when these keys are missing. This improves error handling and prevents server crashes when creating templates with incomplete settings.
- Use `default=str` in `json.dumps` to handle non-serializable objects
- Return proper HTTP 304 response with ETag header instead of raising exception
- Ensure consistent ETag generation for template caching
- Add optional `tags` query parameter to `/nodes` and `/templates` endpoints
- Support filtering by tags in format "key:value" with multiple tags ANDed together
- Example: `?tags=vendor:cisco&tags=model:7200` filters nodes/templates with both tags
- Maintain backward compatibility for existing API usage without tags parameter
Add three new optional fields to the template schema:
- vendor: Device vendor (e.g., Cisco, Juniper, Huawei)
- model: Device model (e.g., ISR4451-X, MX204, NE40E)
- netmiko_device_type: Netmiko device type for automation (e.g., cisco_ios, juniper_junos, huawei)
These fields enable AI/LLM integration to determine the appropriate
Netmiko device type when automating network device configuration.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
asyncio.get_running_loop() raises RuntimeError when emit() is called
from a thread without an active event loop (e.g. when the disk space
check in project_manager triggers a log.warning notification from a
threadpool worker).
This causes a 500 Internal Server Error on project creation/open when
disk usage is high, instead of the intended warning notification.
Wrap the emit loop in try/except RuntimeError so that notifications
are silently dropped when no event loop is available, rather than
crashing the request.
Fixes#2502Fixes#2505
As described in #2568 when multiple clients connect simultaneously, an excessive number of database pool connections are created. This leads to resource exhaustion and connection management issues.
We have introduced the pool_size and max_overflow parameters to better control the database connection pool.
These parameters ensure the database can handle a sufficient number of concurrent connections without over-allocating resources.
Added pool_size and max_overflow arguments to the database initialization.
This change overrides the default initialization configuration where the temporary fix was applied.
Co-Authored-By: Ufi <86113085+ufiking@users.noreply.github.com>
Most VNC clients use the Desktop name in their window title.
Currently this defaults to user@host which means all docker vnc
connections have identical window names of e.g.
SSVNC: gns3@gns3server
This uses the node name instead.
* Offset pci_device_id for network devices by 32 (formerly 4)
to reserve first 32 IDs for non-netdev devices
* This implies a new pci_bridge for the netdevs and
the pci_device_ids starting at 0 (using modulo)
* Fixes a bug in the creation of the qemu command
when the number of qemu pcie devices (storage_controller, disks, …)
was greater than 4 and the number of network devices
saturated the 32 pcie ids of the root bridge
causing qemu not to start.
While try this example with GNS3 branch 3.0 on Ubuntu 20.04 LTS, the API call
```$ curl http://172.17.46.114:3080/v3/users/authenticate -d '{"username": "admin", "password": "admin"}' ``` fails with ```{"detail":[{"loc":["body"],"msg":"value is not a valid dict","type":"type_error.dict"}]}```.
The additional parameter appended to curl fixes this ```{"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhZG1pbiIsImV4cCI6MTYzMTI4NTc4NX0.kT1dAN4v1vHMTBJO2UaI2I7yAFhnSpBU9iqmdDuwtAQ","token_type":"bearer"} ```
Found after googling for the error above in
FastAPI 0.65.2 POST request fails with "value is not a valid dict" when using the Requests library; 0.65.1 works (with a caveat) #3373https://github.com/tiangolo/fastapi/issues/3373#issuecomment-886745123
Add enable SSL config validator.
Strict configuration file validation: any error will prevent the server to start.
Core server logic moved to a Server class.
- **[JWT Token Flow](./web-wireshark-jwt-token-flow.md)** - JWT token transmission path in Web Wireshark
- Key point: UDPLink only passes through jwt_token, ultimately used by curl command inside Web Wireshark container to authenticate with GNS3 capture stream API
- **[Xpra HTML5 Client](./xpra-html5-client.md)** - Xpra HTML5 client menu control parameters for customizing the web interface
### uBridge Permission
- **[uBridge Permission Issue](./gns3-ubridge-permission.md)** - Docker containers fail to start due to missing CAP_NET_ADMIN/CAP_NET_RAW capabilities on uBridge
- Downstream code directly calls `get_current_jwt_token()`, no need to pass through layers
**Web Wireshark approach**:
- Token needs to be passed across processes (management script is separate process)
- Token needs to be passed across containers (Docker container isolation)
- Cannot use `contextvars`, must pass through command line arguments
## Conclusion
UDPLink does not use this token, it only forwards it to the parent class. Ultimately used by the curl command inside the Web Wireshark container to authenticate with the GNS3 controller's capture stream API.
Token flow: **Client → GNS3 API → Link → UDPLink → Web Wireshark container → GNS3 capture stream API**
Web Wireshark integration uses xpra's built-in HTML5 client to provide browser-based packet capture viewing. The xpra HTML5 client is located at `/usr/share/xpra/www` in the container.
## Configuration Methods
### 1. URL Parameters (Per-Session)
Control toolbar menu items via URL query parameters (default: true):
| Parameter | Menu Item | Description |
|-----------|-----------|-------------|
| xpramenu | Xpra Menu | Main menu (Server, Information submenus) |
| open_windows | Open Windows | List of open windows |
description:This skill should be used when the user asks to "record memory", "save to memory", "remember this", "create a memory", "add to memory", or discusses documenting technical decisions, architectural choices, or important case studies for the project. Use this skill to record project knowledge to the .claude/memory/ directory.
version:1.0.0
---
# Memory Skill
## Overview
Record project-related technical decisions, important case studies, and lessons learned to the project memory directory, ensuring critical knowledge is managed with the code repository.
## When This Skill Activates
Activate this skill when user requests involve:
- "Record to memory", "save to memory", "add to memory"
* Catch exceptions when computing image checksums. Ref https://github.com/GNS3/gns3-server/issues/2228
@@ -194,6 +490,78 @@
* Add Python 3.12 support.
* Fix issue with importlib.resources.files() and Python 3.9
## 3.0.0a5 27/10/2023
* Bundle web-ui v3.0.0a5
* Fix L2IOU "failed code signing checks" when IOU base file name is >= 63 characters
* Python 3.12 support
* Add igb Qemu adapter
* Change "ip cef" to "no ip cef" in IOU default configs. Fixes #2298
* Drop support for Python 3.7 and upgrade dependencies
* Fix compute authentication for websocket endpoints
* Add Qemu IGB network device
## 3.0.0a4 18/10/2023
* Bundle web-ui v3.0.0a4
* Do not enforce Compute.Audit and Template.Audit privileges due to current web-ui limitations
* Support to create empty disk images on the controller
* Fix issue with importlib.resources.files() and Python 3.9
* New RBAC system with resource pools support.
* Use controller vars file to store version and appliance etag
* Pydantic v2 migration
* Allow connection to ws console over IPv6
* Allow computes to be dynamically or manually allocated
* Add UEFI boot mode option for Qemu VMs
* Mark VMware and VirtualBox support as deprecated
* Make port name for custom adapters optional. Fixes https://github.com/GNS3/gns3-web-ui/issues/1430
* Support for database schema migrations using alembic
* Add config option to change the server name. Ref #2149
* Option to disable image discovery and do not scan parent directory
* Allow raw images by default. Fixes https://github.com/GNS3/gns3-server/issues/2097
* Fix bug when creating Dynamips router with chassis setting
* Stricter checks to create/update an Ethernet switch and add tests
* Fix schema for removing WICs from Cisco routers. Fixes #3392
* Fix some issues with HTTP notification streams
* API endpoint to get the locked status of a project
* Global project lock and unlock
* Require name for custom adapters. Fixes #2098
* Allow empty adapter slots for Dynamips templates. Ref https://github.com/GNS3/gns3-gui/issues/3373
* Custom adapters should not be in node (compute) properties returned to clients. Fixes https://github.com/GNS3/gns3-gui/issues/3366
* Optionally allow Qemu raw images
* Ignore image detection for IOU user libraries in image directory
* Checks for valid hostname on server side for Dynamips, IOU, Qemu and Docker nodes
* Only check files (not directories) when looking for new images on file system.
* Support user defined loader/libraries to run IOU
* Remove explicit Response for VPCS endpoints returning HTTP 204 status code
* Remove explicit Response for endpoints returning HTTP 204 status code
* Make 'vendor_url' and 'maintainer_email' optional for template validation.
* Allow auth token to be passed as a URL param
* Add controller endpoints to get VirtualBox VMs, VMware VMs and Docker images
* Detect new images added to the default image directory. * Images can be present before the server starts or while it is running * Images are recorded in the database
* Support delete Qemu disk image from API Return the real disk image name in the 'hdx_disk_image_backed' property for Qemu VMs
* Fix ComputeConflictError import
* Handle creating Qemu disk images and resizing
* Finish to clean up local setting usage. Ref #1460
* "Local" command line parameter is only for stopping a server that has been started by the desktop GUI
* Fix AsyncSession handling after breaking changes in FastAPI 0.74.0 See https://github.com/tiangolo/fastapi/releases/tag/0.74.0 for details.
* Detect image type instead of requesting it from user
* Add connect endpoint for computes Param to connect to compute after creation Report compute unauthorized HTTP errors to client
* Replace CORS origins by origin regex
* Allow empty compute_id. Ref #1657
* Secure controller to compute communication using HTTP basic authentication
* Secure websocket endpoints
* Allocate compute when compute_id is unset
* Return the current controller hostname/IP from any compute
* Remove Qemu legacy networking support
* Appliance management refactoring: * Install an appliance based on selected version * Each template have unique name and version * Allow to download an appliance file
* Add isolate and unisolate endpoints. Ref https://github.com/GNS3/gns3-gui/issues/3190
* Allow images to be stored in subdirs and used by templates.
* Use uuid5 to create new compute_id. Fixes #1641 #1887
* Migrate PCAP streaming code to work with FastAPI.
* Refactor WebSocket console code to work with FastAPI. Fix endpoint routes.
## 2.2.43 19/09/2023
* Force English output for VBoxManage. Fixes #2266
@@ -276,6 +644,28 @@
* Only use importlib_resources for Python <= 3.9. Fixes #2147
* Support when the user field defined in Docker container is an ID. Fixes #2134
## 3.0.0a3 27/12/2022
* Add web-ui v3.0.0a3
* Add config option to change the server name. Ref #2149
* Option to disable image discovery and do not scan parent directory
* Allow raw images by default. Fixes https://github.com/GNS3/gns3-server/issues/2097
* Fix bug when creating Dynamips router with chassis setting
* Stricter checks to create/update an Ethernet switch and add tests
* Fix schema for removing WICs from Cisco routers. Fixes #3392
* Fix issues with VMnet interface on macOS >= 11.0. Ref #3381
* Use importlib_resources instead of pkg_resources and install built-in appliances in config dir.
* Fix console vnc don't use configured ports in some case. Fixes #2111
* Add missing VMware settings in gns3_server.conf
* Make version PEP 440 compliant
* Support for Python 3.11
* Allow for more dependency versions at patch level
* gns3.service.openrc: make openrc script posix compliant
* fix: use exact match to find interface in windows to avoid get wrong interface
## 2.2.35.1 10/11/2022
* Re-release Web-Ui v2.2.35
@@ -295,6 +685,154 @@
* gns3.service.openrc: make openrc script posix compliant
* fix: use exact match to find interface in windows to avoid get wrong interface
## 3.0.0a2 06/09/2022
* Add web-ui v3.0.0a2
* Upgrade FastAPI to v0.82.0
* API endpoint to get the locked status of a project
* Global project lock and unlock
* Update appliance files
* Require name for custom adapters. Fixes #2098
* Allow empty adapter slots for Dynamips templates. Ref https://github.com/GNS3/gns3-gui/issues/3373
* Use original $PATH in init.sh for Docker containers. Ref #2069
## 3.0.0a1 04/08/2022
* Bundle gns3-web-ui v3.0.0a1
* Use default symbol theme if none is provided when loading appliances
* Allow default symbol theme to be configured in config file
* Optionally allow Qemu raw images
* Ignore image detection for IOU user libraries in image directory
* Don't show optional token param in API docs
* Fix check for 32-bit in ELF header
* Checks for valid hostname on server side for Dynamips, IOU, Qemu and Docker nodes
* Only check files (not directories) when looking for new images on file system.
* Support user defined loader/libraries to run IOU
* Make 'vendor_url' and 'maintainer_email' optional for template validation.
* Allow auth token to be passed as a URL param
* HTTP middleware create issues when streaming project archive
* Add zstandard compression support for project export
* Make sure that the temporary image file is removed after uploading an image
* Do not cache to md5sum file in some situations
* Detect new images added to the default image directory. * Images can be present before the server starts or while it is running * Images are recorded in the database
* Support delete Qemu disk image from API Return the real disk image name in the 'hdx_disk_image_backed' property for Qemu VMs
* Handle creating Qemu disk images and resizing
* Finish to clean up local setting usage. Ref #1460
* "Local" command line parameter is only for stopping a server that has been started by the desktop GUI
* Fix AsyncSession handling after breaking changes in FastAPI 0.74.0 See https://github.com/tiangolo/fastapi/releases/tag/0.74.0 for details.
* Detect image type instead of requesting it from user
* Drop Python 3.6 support and require Python >= 3.7
* Drop Windows support
* Add connect endpoint for computes Param to connect to compute after creation Report compute unauthorized HTTP errors to client
* Replace CORS origins by origin regex
* Change default config settings
* Update Docker image for tests
* Fix calls to static methods in server.py
* Do not require the local server param to open a .gns3 file. Fixes https://github.com/GNS3/gns3-gui/issues/2421 Ref #1460
* Do not automatically install appliance after uploading image
* Ignore OSError when closing websocket
* Allow empty compute_id. Ref #1657
* Secure controller to compute communication using HTTP basic authentication
* Secure websocket endpoints
* Fix issue when updating a template
* Allocate compute when compute_id is unset
* Return the current controller hostname/IP from any compute
* Remove Qemu legacy networking support
* Add a custom version to an appliance
* Appliance management refactoring: * Install an appliance based on selected version * Each template have unique name and version * Allow to download an appliance file
* Finalize image management refactoring and auto install appliance if possible
* Sqlite doesn't allow BigInteger to be used as an primary key with autoincrement
* Add isolate and unisolate endpoints. Ref https://github.com/GNS3/gns3-gui/issues/3190
* Small db tables adjustments
* Add index for "name" field in role table
* Allow images to be stored in subdirs and used by templates.
* Option to prune images when deleting template.
* Associate images when creating or updating a template.
* Add prune images endpoint. Use many-to-many relationship between images and templates.
* Check if user has the right to add a permission
* Only use the necessary HTTP methods for default permissions
* Add /permissions/prune to delete orphaned permissions
* Check a permission matches an existing route before it is allowed to be created.
* Remove busybox and copy system busybox in setup.py
* Save image size + start to automatic template creation based on image checksum.
* Upgrade dependencies
* Fix "-machine accel=tcg" check
* Allow logged in user to change some of its data. Administrators can lock users using the `is_active` field.
* Change RBAC field names from builtin to is_builtin
* Add user permissions + RBAC tests.
* Add description for user permission.
* Save/restore appliances Etag.
* Allow to set the initial super admin username / password in server config file. Ref #1857
* Require authentication for get_user_memberships endpoint.
* Change method to prevent forbidden directory traversal. Ref #1894
* Add user groups support.
* Add delete cascade on foreign keys for appliance table
* Enable SQL foreign key support for SQLite
* Add missing CORS origins.
* Show topology path when check topology schema fails.
* Protect controller notification endpoints. Ref #1888 (WebSocket endpoint is not secured, it takes an optional token).
* Use uuid5 to create new compute_id. Fixes #1641 #1887
* Protect the API and add alternative authentication endpoint.
* Secure users API and handle manual password recovery.
* Add default super admin account in controller db.
* Complete type annotations for API endpoints.
* Detect the app is exiting and avoid reconnecting to computes.
* Move schemas between compute and controller subpackages
* Remove traceng code.
* Move error responses to API routers.
* Wait for local compute to be started. Don't reconnect to local compute when server is being stopped.
* Rename ssl and auth configuration file settings. Add enable SSL config validator. Strict configuration file validation: any error will prevent the server to start. Core server logic moved to a Server class.
* Generate new config for each test. Fixes tests.
* Use Pydantic to validate the server config file.
* Add symbol dimensions endpoint and SSL support for packet capture with remote HTTPS server.
* Save computes to database
* Generate a new list in template schema defaults.
* Generate JWT secret key if none is configured in the config file. Change location of the database.
* User authentication with tests.
* Refactor tests and start work on database integration.
* Move endpoints to routes & preparations to use a database.
* Providing the path to create a project is now deprecated.
* Add back script to create a self-signed SSL certificate.
* Make sure all HTTP exceptions return JSON with a "message" field instead of "detail"
* Make Swagger Ui the default for API documentation
* Move to version 3 of the REST API. Rename packet capture endpoints.
* Use pydantic for data validation (instead of jsonschema) Fix/improve various pydantic schema models.
* Automate API documentation publishing.
* Publish API documentation generated by FastAPI.
* Overwrite uvicorn loggers.
* Do not automatically connect to local compute.
* Add HTTP client to reuse the aiohttp session where needed. Remove unnecessary aiohttp exceptions.
* Warn not to use the private compute API. Fixes #1593.
* Migrate PCAP streaming code to work with FastAPI.
* Refactor WebSocket console code to work with FastAPI. Fix endpoint routes.
* Use dependencies and group common HTTP responses in endpoints.
* Migration to FastAPI
* Prioritize the config disk over HD-D for Qemu VMs. Fixes https://github.com/GNS3/gns3-gui/issues/3036
* Create config disk property false by default for Qemu templates
* Set default disk interface type to "none". Fail-safe: use "ide" if an image is set but no interface type is configured. Use the HDA disk interface type if none has been configured for HDD.
* Add explicit option to automatically create or not the config disk. Off by default.
* Auxiliary console support for Qemu. Ref #2873 Improvements for auxiliary console support for Docker and Dynamips.
* Fix AUX console not allocated for Dynamips IOS routers.
* Disallow to rename a running node. Fixes https://github.com/GNS3/gns3-gui/issues/2499
* Support to reset all console connections. Ref https://github.com/GNS3/gns3-server/issues/1619
* Support to reset links. Fixes https://github.com/GNS3/gns3-server/issues/1620
* Add maxcpus property for Qemu VMs. Ref #1674
* QEMU config disk support
* Read folder structure correctly for custom symbols. Fixes https://github.com/GNS3/gns3-gui/issues/2856
* Add total RAM, CPUs and disk size to servers summary as well as disk usage in percent. Fixes https://github.com/GNS3/gns3-server/issues/1532
* Resource constraints for Docker VMs.
* Update IOUtools. Ref #1627
* Use parent directory as working directory for project duplication and snapshots. Fixes https://github.com/GNS3/gns3-gui/issues/2909
* Support for "usage" for "Cloud" nodes. Fixes https://github.com/GNS3/gns3-gui/issues/2887 Allow "usage" for all builtin nodes (not exposed in Ui).
## 2.2.34 28/08/2022
* Use original $PATH in init.sh for Docker containers. Ref #2069
The GNS3 server manages emulators and other virtualization software such as Dynamips, Qemu/KVM, Docker, VPCS, VirtualBox and VMware Workstation.
Clients like the [GNS3 GUI](https://github.com/GNS3/gns3-gui/) and the [GNS3 Web UI](https://github.com/GNS3/gns3-web-ui/) control the server using a HTTP REST API.
- Reduces installation size for users who don't need specific features
- Supports restricted environments (government, education, corporate) where certain libraries may not be allowed
- Faster installation for basic GNS3 usage
- Allows users to choose only the features they need
**Note:** If you install without optional extras, the server will work normally but optional features will be disabled. You can add features later by running the appropriate install command.
**Uninstalling AI Copilot:**
To remove AI Copilot dependencies:
```shell
gns3server-uninstall-ai-copilot
```
This will remove all AI Copilot dependencies while keeping the core functionality intact. The server will continue to work, but AI features will return a 501 (Not Implemented) status code.
The downside of this method is you will have to manually install all dependencies (see below).
Please see our [documentation](https://docs.gns3.com/docs/getting-started/installation/linux) for more details.
### Software dependencies
In addition to Python dependencies, other software may be required, recommended or optional.
* [uBridge](https://github.com/GNS3/ubridge/) is required, it interconnects the nodes.
* [Dynamips](https://github.com/GNS3/dynamips/) is required for running IOS routers (using real IOS images) as well as the internal switches and hubs.
* [VPCS](https://github.com/GNS3/vpcs/) is recommended, it is a builtin node simulating a very simple computer to perform connectivity tests using ping, traceroute etc.
* Qemu is strongly recommended as most node types are based on Qemu, for example Cisco IOSv and Arista vEOS.
* libvirt is recommended as it's needed for the NAT cloud.
* Docker is optional, some nodes are based on Docker.
* mtools is recommended to support data transfer to/from QEMU VMs using virtual disks.
* i386-libraries of libc and libcrypto are optional, they are only needed to run IOU based nodes.
Note that Docker needs the script program (`bsdutils` or `util-linux` package), when running a Docker VM and a static busybox during installation (python3 setup.py install / pip3 install / package creation).
## Development
### Setting up
These commands will install the server with core Python dependencies:
```shell
git clone https://github.com/GNS3/gns3-server
cd gns3-server
git checkout 3.0
python3 -m venv venv-gns3server
source venv-gns3server/bin/activate
python3 -m pip install .
gns3server
python3 -m gns3server
```
To run tests use:
**For AI Copilot development**, install with additional dependencies:
``` {.bash}
python3 -m pytest tests
```shell
python3 -m pip install .[ai-copilot,dev]
```
**For development (tests and linting)**:
```shell
python3 -m pip install .[dev]
```
You will have to manually install other software dependencies (see above), for Dynamips, VPCS and uBridge the easiest is to install from our PPA.
### Docker container
For development, you can run the GNS3 server in a container
Alternatively, you can run the GNS3 server in a container
Please use GitHub's report a vulnerability feature. More information can be found in https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability
The API documentation can be accessed when running the server locally:
* On `http://IP:PORT/docs` to see with Swagger UI (i.e. `http://localhost:3080/docs`)
* On `http://IP:PORT/redoc` to see with ReDoc (i.e. `http://localhost:3080/redoc`)
The documentation can also be viewed [online](http://apiv3.gns3.net) however it may not be the most up-to-date version since it needs manually synchronization with the current code. Also, you cannot use this to interact with a GNS3 server.
### Branches
#### master
master is the next stable release, you can test it in your day-to -day activities.
Bug fixes or small improvements pull requests go here.
3.x development brand for the next major release.
**Never** use this branch for production. Pull requests for major new features go here.
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
> This documentation is organized by AI with reference to actual code. AI can make mistakes — please verify against the source code when in doubt.
# GNS3 Server Documentation
---
## License
This documentation is licensed under the **Creative Commons Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0)**.
⚠️ **Important - ShareAlike Requirement**: If you create derivative works based on this documentation (including software that incorporates substantial portions of the documentation), your work must also be licensed under **CC BY-SA 4.0 or a compatible license** (such as GPLv3).
- 📄 **Full License Text**: See [docs/LICENSE](./LICENSE)
Architecture and minimum configuration for setting up GNS3 Controller with remote Compute nodes. Covers compute node config, controller registration, and multi-compute deployment.
### Statistics API (`features/statistics-api.md`)
Aggregated server statistics API (`GET /v3/statistics`) for monitoring dashboards. Collects compute resources, project/node/link counts, and Web Wireshark container status in a single request.
Browser-based VNC console access via WebSocket. The Controller acts as WebSocket-to-WebSocket relay, and Compute bridges WebSocket to TCP for QEMU/Docker VMs. Supports noVNC clients.
### API Error Responses (`features/api-error-responses.md`)
Unified error response format across all GNS3 API endpoints. Documents HTTP status codes, error types, and client-side error handling patterns.
### Web Wireshark (`features/web-wireshark-business-process.md`)
Web-based packet capture analysis using Docker + xpra HTML5 client. Zero-install Wireshark experience directly in the browser, integrated with GNS3 topologies.
- [Template-Based Configuration with HITL](gns3-copilot/template-based-configuration-roadmap.md) — Jinja2 templates with human-in-the-loop confirmations for device configuration and node creation
---
## Known Issues (`bugs/`)
- [Telnet Server Connection Race Condition](bugs/telnet-server-connection-race-condition.md) — `getpeername()` error when client disconnects during connection setup (High severity, Open)
---
## Development Setup (`development-setup.md`)
Quick-start guide for Ubuntu 24.04: install via PPA, set up dependencies, and run gns3-server from source.
---
## Related Documentation
- [GNS3 Server API Documentation](https://api.gns3.com/) — Interactive API docs (also available locally via `redoc.html`)
- [GNS3 Web UI Documentation](https://docs.gns3.com/)
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/cloud/nodes/3c524997-ecb4-43c8-b0eb-4978446be73d/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/cloud/nodes/3c524997-ecb4-43c8-b0eb-4978446be73d/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/cloud/nodes/5def67e9-a974-4da2-9cd3-17866ede1898/adapters/0/ports/0/stop_capture' -d '{}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/cloud/nodes/5def67e9-a974-4da2-9cd3-17866ede1898/adapters/0/ports/0/stop_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/docker/nodes/937a4da0-7334-4fee-a351-5433acaaa298/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/docker/nodes/937a4da0-7334-4fee-a351-5433acaaa298/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/docker/nodes/e44e037c-3b3e-4172-aff7-b9bb510646c6/adapters/0/ports/0/stop_capture' -d '{}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/docker/nodes/e44e037c-3b3e-4172-aff7-b9bb510646c6/adapters/0/ports/0/stop_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/iou/nodes/b63d611d-066b-4673-ad6c-c0e8a93cedbb/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/iou/nodes/b63d611d-066b-4673-ad6c-c0e8a93cedbb/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/nat/nodes/bc78e678-408d-4d03-9670-c29da452f6c7/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/nat/nodes/bc78e678-408d-4d03-9670-c29da452f6c7/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/qemu/nodes/40fc7ce3-f4fe-469e-a94a-fb95906d9e22/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/qemu/nodes/40fc7ce3-f4fe-469e-a94a-fb95906d9e22/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/qemu/nodes/4258adbd-3115-4b8f-b751-cb117dcff450/adapters/0/ports/0/stop_capture' -d '{}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/qemu/nodes/4258adbd-3115-4b8f-b751-cb117dcff450/adapters/0/ports/0/stop_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/traceng/nodes/770d23d8-e568-4fc4-8497-216c2e129d53/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/traceng/nodes/770d23d8-e568-4fc4-8497-216c2e129d53/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/traceng/nodes/2a0e5c7d-6773-45a3-886c-d19e329eaeba/adapters/0/ports/0/stop_capture' -d '{}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/traceng/nodes/2a0e5c7d-6773-45a3-886c-d19e329eaeba/adapters/0/ports/0/stop_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/virtualbox/nodes/e99d891a-06ed-4923-9110-4dfae366af6d/adapters/0/ports/0/start_capture' -d '{"capture_file_name": "test.pcap", "data_link_type": "DLT_EN10MB"}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/virtualbox/nodes/e99d891a-06ed-4923-9110-4dfae366af6d/adapters/0/ports/0/start_capture HTTP/1.1
curl -i -X POST 'http://localhost:3080/v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/virtualbox/nodes/27bdd057-dedc-424e-9593-3ea522aa7d1f/adapters/0/ports/0/stop_capture' -d '{}'
POST /v2/compute/projects/a1e920ca-338a-4e9f-b363-aa607b09dd80/virtualbox/nodes/27bdd057-dedc-424e-9593-3ea522aa7d1f/adapters/0/ports/0/stop_capture HTTP/1.1
Loaded 100 of 1405 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.