mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-09-25 13:20:23 +03:00
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
258 lines
6.9 KiB
Python
258 lines
6.9 KiB
Python
"""
|
|
GNS3 File Index Manager
|
|
|
|
This module provides functionality to manage an index of files in GNS3 projects.
|
|
Since GNS3 API doesn't provide a way to list files, we maintain an index
|
|
file to track files written to each project.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Any
|
|
|
|
from gns3_copilot.gns3_client import Project, get_gns3_connector
|
|
|
|
# Configure logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Load environment variables
|
|
|
|
# Index file name (stored in project directory)
|
|
INDEX_FILE_NAME = ".gns3_copilot_file_index.json"
|
|
|
|
|
|
def _get_index_path(project_id: str) -> str:
|
|
"""
|
|
Get the path to the index file for a project.
|
|
|
|
Args:
|
|
project_id: The project ID
|
|
|
|
Returns:
|
|
The path to the index file (relative to project directory)
|
|
"""
|
|
return INDEX_FILE_NAME
|
|
|
|
|
|
def load_file_index(project: Project) -> dict[str, Any]:
|
|
"""
|
|
Load the file index for a project.
|
|
|
|
Args:
|
|
project: GNS3 Project instance
|
|
|
|
Returns:
|
|
A dictionary containing the index data, or an empty index if not found
|
|
"""
|
|
if project.project_id is None:
|
|
raise ValueError("Project ID must be set")
|
|
|
|
index_path = _get_index_path(project.project_id)
|
|
|
|
try:
|
|
content = project.get_file(path=index_path)
|
|
index_data = json.loads(content)
|
|
|
|
# Validate index structure
|
|
if not isinstance(index_data, dict):
|
|
logger.warning("Invalid index structure, creating new index")
|
|
return _create_empty_index(project.project_id)
|
|
|
|
if "files" not in index_data:
|
|
index_data["files"] = []
|
|
|
|
logger.info(
|
|
"Loaded file index for project %s with %d files",
|
|
project.project_id,
|
|
len(index_data["files"]),
|
|
)
|
|
return index_data
|
|
|
|
except Exception as e:
|
|
logger.info(
|
|
"No existing file index found for project %s, creating new one: %s",
|
|
project.project_id,
|
|
e,
|
|
)
|
|
return _create_empty_index(project.project_id)
|
|
|
|
|
|
def save_file_index(project: Project, index_data: dict[str, Any]) -> None:
|
|
"""
|
|
Save the file index for a project.
|
|
|
|
Args:
|
|
project: GNS3 Project instance
|
|
index_data: The index data to save
|
|
|
|
Raises:
|
|
ValueError: If failed to save the index
|
|
"""
|
|
if project.project_id is None:
|
|
raise ValueError("Project ID must be set")
|
|
|
|
index_path = _get_index_path(project.project_id)
|
|
|
|
try:
|
|
# Ensure project_id is in the index
|
|
index_data["project_id"] = project.project_id
|
|
|
|
# Save as JSON with indentation for readability
|
|
content = json.dumps(index_data, indent=2, ensure_ascii=False)
|
|
|
|
project.write_file(path=index_path, data=content)
|
|
logger.info("Saved file index for project %s", project.project_id)
|
|
|
|
except Exception as e:
|
|
logger.error(
|
|
"Failed to save file index for project %s: %s", project.project_id, e
|
|
)
|
|
raise ValueError(f"Failed to save file index: {str(e)}") from e
|
|
|
|
|
|
def _create_empty_index(project_id: str) -> dict[str, Any]:
|
|
"""
|
|
Create an empty file index structure.
|
|
|
|
Args:
|
|
project_id: The project ID
|
|
|
|
Returns:
|
|
A dictionary with empty index structure
|
|
"""
|
|
return {
|
|
"project_id": project_id,
|
|
"files": [],
|
|
"created_at": datetime.now().isoformat(),
|
|
"updated_at": datetime.now().isoformat(),
|
|
}
|
|
|
|
|
|
def add_file_to_index(
|
|
project: Project,
|
|
path: str,
|
|
size: int | None = None,
|
|
) -> dict[str, Any]:
|
|
"""
|
|
Add or update a file in the project index.
|
|
|
|
Args:
|
|
project: GNS3 Project instance
|
|
path: The file path
|
|
size: Optional file size in bytes
|
|
|
|
Returns:
|
|
The updated index data
|
|
|
|
Raises:
|
|
ValueError: If failed to update the index
|
|
"""
|
|
try:
|
|
# Load existing index
|
|
index_data = load_file_index(project)
|
|
|
|
# Check if file already exists
|
|
file_entry = next((f for f in index_data["files"] if f["path"] == path), None)
|
|
|
|
now = datetime.now().isoformat()
|
|
|
|
if file_entry:
|
|
# Update existing file
|
|
file_entry["updated_at"] = now
|
|
if size is not None:
|
|
file_entry["size"] = size
|
|
logger.info("Updated file in index: %s", path)
|
|
else:
|
|
# Add new file
|
|
new_entry: dict[str, Any] = {
|
|
"path": path,
|
|
"created_at": now,
|
|
"updated_at": None,
|
|
}
|
|
if size is not None:
|
|
new_entry["size"] = size
|
|
|
|
index_data["files"].append(new_entry)
|
|
logger.info("Added file to index: %s", path)
|
|
|
|
# Update index timestamp
|
|
index_data["updated_at"] = now
|
|
|
|
# Save index
|
|
save_file_index(project, index_data)
|
|
|
|
return index_data
|
|
|
|
except Exception as e:
|
|
logger.error("Failed to add file to index: %s", e)
|
|
raise ValueError(f"Failed to add file to index: {str(e)}") from e
|
|
|
|
|
|
def get_file_list(project: Project) -> list[dict[str, Any]]:
|
|
"""
|
|
Get the list of files from the project index.
|
|
|
|
Args:
|
|
project: GNS3 Project instance
|
|
|
|
Returns:
|
|
A list of file entries
|
|
"""
|
|
try:
|
|
index_data = load_file_index(project)
|
|
files = index_data.get("files", [])
|
|
return files if isinstance(files, list) else []
|
|
except Exception as e:
|
|
logger.error("Failed to get file list: %s", e)
|
|
return []
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Test the file index manager
|
|
print("=" * 80)
|
|
print("Testing GNS3 File Index Manager")
|
|
print("=" * 80)
|
|
|
|
try:
|
|
# Create connector and project
|
|
connector = get_gns3_connector()
|
|
if connector is None:
|
|
print("ERROR: Failed to create GNS3 connector")
|
|
exit(1)
|
|
|
|
# Replace with actual project ID for testing
|
|
test_project_id = "your-project-uuid"
|
|
print(f"\nTesting with project: {test_project_id}")
|
|
print("NOTE: Replace 'your-project-uuid' with actual project ID")
|
|
|
|
# Create project instance
|
|
project = Project(project_id=test_project_id, connector=connector)
|
|
|
|
# Load index
|
|
print("\n1. Loading file index...")
|
|
index_data = load_file_index(project)
|
|
print(f" Index loaded: {len(index_data.get('files', []))} files")
|
|
|
|
# Add file to index
|
|
print("\n2. Adding file to index...")
|
|
updated_index = add_file_to_index(project, "test_file.txt", size=1024)
|
|
print(f" File added. Total files: {len(updated_index['files'])}")
|
|
|
|
# Get file list
|
|
print("\n3. Getting file list...")
|
|
file_list = get_file_list(project)
|
|
print(" Files in index:")
|
|
for file_entry in file_list:
|
|
print(f" - {file_entry['path']}")
|
|
|
|
print("\n" + "=" * 80)
|
|
print("Test completed successfully!")
|
|
print("=" * 80)
|
|
|
|
except Exception as e:
|
|
print(f"\nERROR: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|