mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-17 23:40:39 +03:00
delete doc
This commit is contained in:
parent
578f79cd6b
commit
a6c33061c4
@ -1,180 +0,0 @@
|
||||
# Datetime Timezone Issue
|
||||
|
||||
## Problem Description
|
||||
|
||||
The API returns datetime strings without timezone suffixes, causing frontend JavaScript to parse them as local time instead of UTC time.
|
||||
|
||||
### Example
|
||||
|
||||
| Aspect | Value |
|
||||
|--------|-------|
|
||||
| Actual time (Beijing) | 2026-03-07 01:30 |
|
||||
| Backend returns | `2026-03-06T16:31:36.547762` (no timezone) |
|
||||
| Frontend displays | March 6, 16:31 |
|
||||
| Should display | March 7, 00:31 (UTC 16:31 + 8 hours) |
|
||||
|
||||
### Root Cause
|
||||
|
||||
- Backend stores UTC time in database as naive datetime (no timezone info)
|
||||
- FastAPI's `jsonable_encoder` serializes datetime as ISO 8601 **without timezone suffix**
|
||||
- JavaScript `new Date()` treats strings without 'Z' or timezone offset as **local time**
|
||||
|
||||
```
|
||||
Backend intention: 2026-03-06T16:31:36Z (UTC)
|
||||
Actually returned: 2026-03-06T16:31:36.547762 (no timezone)
|
||||
JavaScript parses as: local time 16:31
|
||||
Should be: UTC 16:31 → Beijing time 00:31 (next day)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontend Solutions
|
||||
|
||||
### Solution 1: Use dayjs UTC Parsing (Recommended)
|
||||
|
||||
```typescript
|
||||
import dayjs from 'dayjs';
|
||||
import utc from 'dayjs/plugin/utc';
|
||||
import timezone from 'dayjs/plugin/timezone';
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
// Parse naive datetime as UTC
|
||||
const createdAt = '2026-03-06T16:31:36.547762';
|
||||
const date = dayjs.utc(createdAt).tz('Asia/Shanghai');
|
||||
console.log(date.format('YYYY-MM-DD HH:mm')); // 2026-03-07 00:31
|
||||
```
|
||||
|
||||
### Solution 2: Add 'Z' Suffix Manually
|
||||
|
||||
```typescript
|
||||
// Utility function to normalize API dates
|
||||
function parseAPIDate(dateStr: string): Date {
|
||||
// Add 'Z' suffix if no timezone info present
|
||||
const normalized = dateStr.includes('Z') || dateStr.includes('+')
|
||||
? dateStr
|
||||
: `${dateStr}Z`;
|
||||
return new Date(normalized);
|
||||
}
|
||||
|
||||
// Usage
|
||||
const date = parseAPIDate('2026-03-06T16:31:36.547762');
|
||||
console.log(date.toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }));
|
||||
```
|
||||
|
||||
### Solution 3: Global Axios Interceptor (Most Thorough)
|
||||
|
||||
```typescript
|
||||
import axios from 'axios';
|
||||
|
||||
api.interceptors.response.use((response) => {
|
||||
// Recursively normalize all date fields
|
||||
function normalizeDates(obj: any): any {
|
||||
// Match ISO 8601 datetime pattern without timezone
|
||||
if (typeof obj === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(obj)) {
|
||||
return obj.includes('Z') || obj.includes('+') ? obj : `${obj}Z`;
|
||||
}
|
||||
if (Array.isArray(obj)) {
|
||||
return obj.map(normalizeDates);
|
||||
}
|
||||
if (obj && typeof obj === 'object') {
|
||||
return Object.fromEntries(
|
||||
Object.entries(obj).map(([k, v]) => [k, normalizeDates(v)])
|
||||
);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
response.data = normalizeDates(response.data);
|
||||
return response;
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Backend Context
|
||||
|
||||
### Current Implementation
|
||||
|
||||
**File**: `gns3server/api/server.py:58-64`
|
||||
|
||||
```python
|
||||
application = FastAPI(
|
||||
title="GNS3 controller API",
|
||||
description="This page describes the public controller API for GNS3",
|
||||
version="v3",
|
||||
docs_url=None,
|
||||
redoc_url=None
|
||||
)
|
||||
```
|
||||
|
||||
**File**: `gns3server/db/models/base.py`
|
||||
|
||||
```python
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
|
||||
class Base:
|
||||
def asjson(self):
|
||||
return jsonable_encoder(self.asdict())
|
||||
```
|
||||
|
||||
### Datetime Flow
|
||||
|
||||
1. Database stores naive datetime (no timezone)
|
||||
2. FastAPI uses `jsonable_encoder` to serialize
|
||||
3. Output format: `YYYY-MM-DDTHH:MM:SS.ffffff` (no 'Z' suffix)
|
||||
4. JavaScript interprets as local time
|
||||
|
||||
### Affected Fields
|
||||
|
||||
- `created_at`
|
||||
- `updated_at`
|
||||
- `last_login`
|
||||
- Any other datetime fields in API responses
|
||||
|
||||
---
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
- [ ] Verify datetime displays correctly in Beijing timezone (UTC+8)
|
||||
- [ ] Test with other timezones (e.g., UTC-5, UTC+0)
|
||||
- [ ] Check daylight saving time transitions (if applicable)
|
||||
- [ ] Verify datetime input/insertion still works correctly
|
||||
|
||||
---
|
||||
|
||||
## Related Files
|
||||
|
||||
- Backend: `gns3server/api/server.py`
|
||||
- Backend: `gns3server/db/models/base.py`
|
||||
- Schemas: `gns3server/schemas/controller/base.py`
|
||||
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
**Copyright © 2025 Yue Guobin (岳国宾)**
|
||||
|
||||
This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
|
||||
International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||

|
||||
|
||||
### Summary
|
||||
|
||||
You are free to:
|
||||
|
||||
- **Share** — Copy and redistribute the material in any medium or format
|
||||
- **Adapt** — Remix, transform, and build upon the material for any purpose
|
||||
|
||||
Under the following terms:
|
||||
|
||||
- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
|
||||
a link to the license, and indicate if changes were made.
|
||||
- **ShareAlike** — If you remix, transform, or build upon the material, you must
|
||||
distribute your contributions under the **same license** (CC BY-SA 4.0).
|
||||
|
||||
Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
|
||||
|
||||
@ -1,179 +0,0 @@
|
||||
# Force Kill (kill -9) Causing Residual Processes Issue
|
||||
|
||||
## Problem Description
|
||||
|
||||
When using `kill -9` to forcibly close the gns3server process, restarting gns3server results in the following errors:
|
||||
|
||||
### 1. Dynamips VM Creation Failure
|
||||
```
|
||||
ERROR gns3server.api.routes.compute:133 Compute node error: Dynamips error when running command 'vm create "R1" 1 c7200
|
||||
': unable to create VM instance 'R1'
|
||||
```
|
||||
|
||||
### 2. Validation Error with project_id as "undefined"
|
||||
```
|
||||
ERROR gns3server.api.server:208 Request validation error in /v3/projects/undefined/nodes/{node_id} (PUT):
|
||||
1 validation error:
|
||||
{'type': 'uuid_parsing', 'loc': ('path', 'project_id'), 'msg': 'Input should be a valid UUID, invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-fA-F-], found `u` at 1', 'input': 'undefined', ...}
|
||||
```
|
||||
|
||||
### 3. TCP Port Still in Use Warning
|
||||
```
|
||||
WARNING gns3server.compute.project:355 Project d672144c-4de9-4a97-a23d-307ddc3ab9b1 has TCP ports still in use: {5001}
|
||||
```
|
||||
|
||||
## Root Cause
|
||||
|
||||
When using `kill -9` to forcibly terminate the gns3server process, gns3server has no opportunity to properly clean up its spawned child processes, leaving the following residual processes running:
|
||||
|
||||
- **Dynamips hypervisor processes** (dynamips)
|
||||
- **VPCS virtual PC processes** (vpcs)
|
||||
- **Docker containers** (although shown as removed in logs, some state may not be cleaned up)
|
||||
- **Other emulator processes**
|
||||
|
||||
These residual processes will:
|
||||
1. Occupy the same port numbers and resource IDs
|
||||
2. Maintain old socket connections
|
||||
3. Cause the newly started gns3server to be unable to reallocate the same resources
|
||||
|
||||
## Solutions
|
||||
|
||||
### Method 1: Manual Cleanup of Residual Processes (Recommended)
|
||||
|
||||
After forcibly closing gns3server, find and clean up residual processes:
|
||||
|
||||
```bash
|
||||
# Find dynamips processes
|
||||
ps aux | grep dynamips
|
||||
|
||||
# Find vpcs processes
|
||||
ps aux | grep vpcs
|
||||
|
||||
# Terminate residual processes
|
||||
killall dynamips
|
||||
killall vpcs
|
||||
```
|
||||
|
||||
### Method 2: Use pkill to Clean Related Processes
|
||||
|
||||
```bash
|
||||
# Clean all GNS3 related processes
|
||||
pkill -9 dynamips
|
||||
pkill -9 vpcs
|
||||
pkill -9 ubridge
|
||||
```
|
||||
|
||||
### Method 3: Check Before Restart
|
||||
|
||||
Before restarting gns3server, ensure there are no residual processes:
|
||||
|
||||
```bash
|
||||
# Check if there are residual GNS3 processes
|
||||
ps aux | grep -E "(dynamips|vpcs|ubridge|gns3)" | grep -v grep
|
||||
```
|
||||
|
||||
## Preventive Measures
|
||||
|
||||
### 1. Use Proper Shutdown Methods
|
||||
|
||||
Prefer the following methods to close gns3server instead of `kill -9`:
|
||||
|
||||
```bash
|
||||
# If using systemd
|
||||
sudo systemctl stop gns3server
|
||||
|
||||
# If running directly
|
||||
# Press Ctrl+C or use normal kill signal
|
||||
kill <gns3server-pid>
|
||||
```
|
||||
|
||||
### 2. Use SIGTERM Instead of SIGKILL
|
||||
|
||||
```bash
|
||||
# Try normal termination first (allows process to clean up)
|
||||
kill -15 <gns3server-pid>
|
||||
|
||||
# Wait a few seconds, if process is still running, then use kill -9
|
||||
sleep 3
|
||||
if ps -p <gns3server-pid> > /dev/null; then
|
||||
kill -9 <gns3server-pid>
|
||||
fi
|
||||
```
|
||||
|
||||
### 3. Implement Automatic Cleanup Script
|
||||
|
||||
You can create a startup script to check and clean up residual processes:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# cleanup_before_start.sh
|
||||
|
||||
# Check and clean residual dynamips processes
|
||||
if pgrep -f dynamips > /dev/null; then
|
||||
echo "Found residual dynamips processes, cleaning up..."
|
||||
killall -9 dynamips
|
||||
fi
|
||||
|
||||
# Check and clean residual vpcs processes
|
||||
if pgrep -f vpcs > /dev/null; then
|
||||
echo "Found residual vpcs processes, cleaning up..."
|
||||
killall -9 vpcs
|
||||
fi
|
||||
|
||||
# Wait for ports to be released
|
||||
sleep 1
|
||||
|
||||
# Start gns3server
|
||||
gns3server
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Why Does kill -9 Cause This Problem?
|
||||
|
||||
1. **SIGKILL signal cannot be captured**: Processes cannot capture or ignore the SIGKILL signal, so there's no chance to execute cleanup code
|
||||
2. **Child processes become orphans**: After the parent process is forcibly terminated, child processes are adopted by init/PID 1, but they don't know the parent has died
|
||||
3. **Resources not released**: Sockets, ports, file locks, and other resources are not properly released
|
||||
4. **State inconsistency**: gns3server's internal state (such as port allocation, ID allocation) is cleared, but actual resources are still occupied
|
||||
|
||||
### Code Locations Involved
|
||||
|
||||
- **Dynamips Process Management**: `gns3server/compute/dynamips/`
|
||||
- **Port Allocation and Tracking**: `gns3server/compute/project.py:355`
|
||||
- **Node Update API**: `gns3server/api/routes/controller/nodes.py:230`
|
||||
|
||||
## Related Issues
|
||||
|
||||
- [ ] Consider automatically detecting and cleaning up residual processes at gns3server startup
|
||||
- [ ] Add process health check mechanism
|
||||
- [ ] Implement more robust port and ID reuse logic
|
||||
- [ ] Add residual process detection and warnings
|
||||
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
**Copyright © 2025 Yue Guobin (岳国宾)**
|
||||
|
||||
This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0
|
||||
International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/).
|
||||
|
||||

|
||||
|
||||
### Summary
|
||||
|
||||
You are free to:
|
||||
|
||||
- **Share** — Copy and redistribute the material in any medium or format
|
||||
- **Adapt** — Remix, transform, and build upon the material for any purpose
|
||||
|
||||
Under the following terms:
|
||||
|
||||
- **Attribution** — You must give appropriate credit to **Yue Guobin (岳国宾)**, provide
|
||||
a link to the license, and indicate if changes were made.
|
||||
- **ShareAlike** — If you remix, transform, or build upon the material, you must
|
||||
distribute your contributions under the **same license** (CC BY-SA 4.0).
|
||||
|
||||
Full license text: [DESIGN_DOCS_LICENSE](../DESIGN_DOCS_LICENSE.md)
|
||||
|
||||
@ -1,209 +0,0 @@
|
||||
# Mypy Static Type Checking Issues
|
||||
|
||||
**Date:** 2026-03-10
|
||||
**Status:** Pending
|
||||
**Priority:** Medium
|
||||
|
||||
## Overview
|
||||
|
||||
This document tracks type checking issues found by `mypy` in the `gns3_copilot` module. These issues should be addressed to improve type safety and catch potential bugs at development time.
|
||||
|
||||
## How to Run Type Checking
|
||||
|
||||
```bash
|
||||
# Install mypy
|
||||
pip install mypy
|
||||
|
||||
# Run type checking on gns3_copilot module
|
||||
mypy gns3server/agent/gns3_copilot/
|
||||
|
||||
# Install missing type stubs
|
||||
mypy --install-types
|
||||
pip install types-requests
|
||||
```
|
||||
|
||||
## Issues Summary
|
||||
|
||||
### Total: 35 Type Errors
|
||||
|
||||
| File | Error Count | Priority |
|
||||
|------|-------------|----------|
|
||||
| chat_sessions_repository.py | 8 | High |
|
||||
| context_manager.py | 5 | High |
|
||||
| agent_service.py | 5 | High |
|
||||
| gns3_topology_reader.py | 2 | Medium |
|
||||
| message_converters.py | 1 | Medium |
|
||||
| connector_factory.py | 1 | Medium |
|
||||
| custom_gns3fy.py | Missing stubs | Low |
|
||||
| display_tools_nornir.py | Missing stubs | Low |
|
||||
| config_tools_nornir.py | Missing stubs | Low |
|
||||
|
||||
## Detailed Issues
|
||||
|
||||
### 1. chat_sessions_repository.py (8 errors)
|
||||
|
||||
**Lines 157, 234, 279, 283, 287, 291, 295**
|
||||
|
||||
#### Error 1: Return value type mismatch (Line 157)
|
||||
```python
|
||||
# Issue: Returning ChatSession | None, but function expects ChatSession
|
||||
error: Incompatible return value type (got "ChatSession | None", expected "ChatSession")
|
||||
error: Argument 1 to "get_session_by_id" has incompatible type "int | None"; expected "int"
|
||||
```
|
||||
|
||||
**Fix:** Add proper null checks and type guards
|
||||
|
||||
#### Error 2: List append type mismatch (Lines 234, 279, 283, 287, 291, 295)
|
||||
```python
|
||||
# Issue: Appending int to list[str]
|
||||
error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
|
||||
```
|
||||
|
||||
**Fix:** Convert integers to strings before appending, or change list type annotation
|
||||
|
||||
---
|
||||
|
||||
### 2. context_manager.py (5 errors)
|
||||
|
||||
**Lines 139, 145, 156, 167, 171**
|
||||
|
||||
```python
|
||||
# Issue: Unsupported indexed assignment on Collection[str]
|
||||
error: Unsupported target for indexed assignment ("Collection[str]")
|
||||
```
|
||||
|
||||
**Problem:** `Collection[str]` is a read-only protocol, doesn't support item assignment.
|
||||
|
||||
**Fix:** Change type annotation to `List[str]` or `MutableSequence[str]`
|
||||
|
||||
---
|
||||
|
||||
### 3. agent_service.py (5 errors)
|
||||
|
||||
**Lines 267, 617, 634, 653, 675**
|
||||
|
||||
```python
|
||||
# Issue: Passing Connection | None to function expecting Connection
|
||||
error: Argument 1 to "ChatSessionsRepository" has incompatible type "Connection | None"; expected "Connection"
|
||||
```
|
||||
|
||||
**Fix:** Add null checks before passing connection parameter, or use assertion
|
||||
|
||||
---
|
||||
|
||||
### 4. gns3_topology_reader.py (2 errors)
|
||||
|
||||
**Lines 137, 138**
|
||||
|
||||
```python
|
||||
# Issue: len() argument has incompatible union type
|
||||
error: Argument 1 to "len" has incompatible type "dict[Any, Any] | str | list[tuple[str, str, str, str]] | None"; expected "Sized"
|
||||
```
|
||||
|
||||
**Fix:** Add null checks and type narrowing before calling `len()`
|
||||
|
||||
---
|
||||
|
||||
### 5. message_converters.py (1 error)
|
||||
|
||||
**Line 151**
|
||||
|
||||
```python
|
||||
# Issue: List type assignment mismatch
|
||||
error: Incompatible types in assignment (expression has type "list[dict[str, Any]]", variable has type "list[ToolCall]")
|
||||
```
|
||||
|
||||
**Fix:** Either convert dict list to ToolCall list, or change variable type annotation
|
||||
|
||||
---
|
||||
|
||||
### 6. connector_factory.py (1 error)
|
||||
|
||||
**Line 368**
|
||||
|
||||
```python
|
||||
# Issue: Calling split() on str | None without null check
|
||||
error: Item "None" of "str | None" has no attribute "split"
|
||||
```
|
||||
|
||||
**Fix:** Add null check before calling `split()` method
|
||||
|
||||
---
|
||||
|
||||
### 7. Missing Type Stubs (Low Priority)
|
||||
|
||||
The following third-party libraries lack type stubs:
|
||||
|
||||
- **requests** → Install: `pip install types-requests`
|
||||
- **netmiko** → No official stubs available
|
||||
- **nornir_netmiko** → No official stubs available
|
||||
|
||||
**Recommendation:** Create inline type ignores or stub files for these libraries.
|
||||
|
||||
---
|
||||
|
||||
## Recommended Fix Strategy
|
||||
|
||||
### Phase 1: High Priority (Critical Type Safety Issues)
|
||||
|
||||
1. **chat_sessions_repository.py**
|
||||
- Fix null safety issues
|
||||
- Ensure proper type conversions for list operations
|
||||
|
||||
2. **context_manager.py**
|
||||
- Change `Collection[str]` to `List[str]` for mutable collections
|
||||
|
||||
3. **agent_service.py**
|
||||
- Add null checks for database connections
|
||||
|
||||
### Phase 2: Medium Priority (Type Annotations)
|
||||
|
||||
4. **gns3_topology_reader.py**
|
||||
- Add type narrowing for union types
|
||||
|
||||
5. **message_converters.py**
|
||||
- Fix type compatibility between dict and ToolCall
|
||||
|
||||
6. **connector_factory.py**
|
||||
- Add null checks before method calls
|
||||
|
||||
### Phase 3: Low Priority (Third-party Stubs)
|
||||
|
||||
7. Install available type stubs (`types-requests`)
|
||||
8. Add `# type: ignore` comments for unavoidable third-party issues
|
||||
|
||||
---
|
||||
|
||||
## Mypy Configuration
|
||||
|
||||
Consider adding a `mypy.ini` or `pyproject.toml` configuration:
|
||||
|
||||
```toml
|
||||
[tool.mypy]
|
||||
python_version = "3.13"
|
||||
warn_return_any = true
|
||||
warn_unused_configs = true
|
||||
disallow_untyped_defs = false # Enable gradually
|
||||
ignore_missing_imports = true # For third-party libs
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = "gns3server.agent.gns3_copilot.*"
|
||||
disallow_untyped_defs = true
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mypy Documentation](https://mypy.readthedocs.io/)
|
||||
- [Python Type Hints](https://docs.python.org/3/library/typing.html)
|
||||
- [Mypy Error Codes](https://mypy.readthedocs.io/en/stable/error_code_list.html)
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- All type issues are in the `gns3_copilot` module
|
||||
- No type errors found in core GNS3 server code during this check
|
||||
- Consider enabling type checking in CI/CD pipeline
|
||||
- Type checking helps catch bugs before runtime
|
||||
Loading…
x
Reference in New Issue
Block a user