refactor: ruff autofixes

This commit is contained in:
Mark Paronyan committed 2026-09-27 15:55:10 +03:00
1 parent 2ac637c662
commit a0450b6bce
455 files changed
+12322 -14762

No files matched your search

+42 -7
View File
@@ -20,16 +20,51 @@ from .common import ErrorMessage
from .version import Version
# Controller schemas
from .controller.links import LinkCreate, LinkUpdate, Link, UDPPortInfo, EthernetPortInfo, LinkCapture, MarkerCreate, MarkerUpdate, MarkerDefinitionCreate
from .controller.computes import ComputeCreate, ComputeUpdate, ComputeVirtualBoxVM, ComputeVMwareVM, ComputeDockerImage, AutoIdlePC, Compute
from .controller.links import (
LinkCreate,
LinkUpdate,
Link,
UDPPortInfo,
EthernetPortInfo,
LinkCapture,
MarkerCreate,
MarkerUpdate,
MarkerDefinitionCreate,
)
from .controller.computes import (
ComputeCreate,
ComputeUpdate,
ComputeVirtualBoxVM,
ComputeVMwareVM,
ComputeDockerImage,
AutoIdlePC,
Compute,
)
from .controller.templates import TemplateCreate, TemplateUpdate, TemplateUsage, Template
from .controller.images import Image, ImageType
from .controller.appliances import ApplianceVersion, ApplianceVersionV8, Appliance
from .controller.drawings import Drawing
from .controller.gns3vm import GNS3VM
from .controller.nodes import NodeCreate, NodeUpdate, NodeDuplicate, NodeCapture, Node
from .controller.projects import ProjectCreate, ProjectUpdate, ProjectDuplicate, Project, ProjectFile, ProjectCompression, NodeFile
from .controller.users import UserCreate, UserUpdate, LoggedInUserUpdate, User, Credentials, UserGroupCreate, UserGroupUpdate, UserGroup
from .controller.projects import (
ProjectCreate,
ProjectUpdate,
ProjectDuplicate,
Project,
ProjectFile,
ProjectCompression,
NodeFile,
)
from .controller.users import (
UserCreate,
UserUpdate,
LoggedInUserUpdate,
User,
Credentials,
UserGroupCreate,
UserGroupUpdate,
UserGroup,
)
# Conditionally import AI-related schemas
try:
@@ -40,7 +75,7 @@ try:
LLMModelConfigResponse,
LLMModelConfigWithSource,
LLMModelConfigInheritedResponse,
LLMModelConfigListResponse
LLMModelConfigListResponse,
)
from .controller.chat import (
OpenAIToolCall,
@@ -49,7 +84,7 @@ try:
OpenAIMessage,
ConversationHistory,
ChatSession,
RenameSession
RenameSession,
)
except ImportError:
# AI schemas are not available (should not happen as they don't depend on external libs)
@@ -89,7 +124,7 @@ from .controller.templates.dynamips_templates import (
C3745DynamipsTemplate,
C3745DynamipsTemplateUpdate,
C7200DynamipsTemplate,
C7200DynamipsTemplateUpdate
C7200DynamipsTemplateUpdate,
)
# Compute schemas
@@ -50,6 +50,5 @@ class ATMSwitchUpdate(ATMSwitchBase):
class ATMSwitch(ATMSwitchBase):
project_id: UUID
status: Optional[NodeStatus] = None
@@ -23,19 +23,16 @@ from ..common import NodeStatus
class HostInterfaceType(str, Enum):
ethernet = "ethernet"
tap = "tap"
class IPAddressFamily(str, Enum):
ipv4 = "ipv4"
ipv6 = "ipv6"
class InterfaceStatus(str, Enum):
up = "up"
down = "down"
@@ -115,7 +112,6 @@ class UDPPort(BaseModel):
class CloudConsoleType(str, Enum):
telnet = "telnet"
ssh = "ssh"
vnc = "vnc"
@@ -160,7 +156,6 @@ class CloudUpdate(CloudBase):
class Cloud(CloudBase):
project_id: UUID
node_id: UUID
ports_mapping: List[Union[EthernetPort, TAPPort, UDPPort]]
+10 -6
View File
@@ -54,11 +54,15 @@ class DockerBase(BaseModel):
usage: Optional[str] = Field(None, description="How to use the Docker container")
start_command: Optional[str] = Field(None, description="Docker CMD entry")
adapters: Optional[int] = Field(None, ge=0, le=99, description="Number of adapters")
mac_address: Optional[str] = Field(None, description="Base MAC address", pattern="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$")
mac_address: Optional[str] = Field(
None, description="Base MAC address", pattern="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$"
)
environment: Optional[str] = Field(None, description="Docker environment variables")
extra_hosts: Optional[str] = Field(None, description="Docker extra hosts (added to /etc/hosts)")
extra_volumes: Optional[List[str]] = Field(None, description="Additional directories to make persistent")
extra_configs: Optional[List[ExtraConfig]] = Field(None, description="Configuration files injected into the container (bind-mounted read-only)")
extra_configs: Optional[List[ExtraConfig]] = Field(
None, description="Configuration files injected into the container (bind-mounted read-only)"
)
startup_config_content: Optional[str] = Field(
None, description="Startup-config content (IOL runner images: materialized into the node's NVRAM at start)"
)
@@ -76,10 +80,11 @@ class DockerCreate(DockerBase):
None, ge=1, le=1022, description="IOL application ID for iol-runner images (allocated by the controller)"
)
image_digest: Optional[str] = Field(
None, pattern=r"^sha256:[a-f0-9]{64}$",
None,
pattern=r"^sha256:[a-f0-9]{64}$",
description="Image id the controller expects for 'image' (sha256:<hex>, resolved from the Docker "
"daemon on the controller host). When set and the compute holds a different image "
"under the same tag, the image is reported as missing so the controller re-syncs it"
"daemon on the controller host). When set and the compute holds a different image "
"under the same tag, the image is reported as missing so the controller re-syncs it",
)
@@ -93,7 +98,6 @@ class DockerUpdate(DockerBase):
class Docker(DockerBase):
container_id: str = Field(
..., min_length=12, max_length=64, pattern="^[a-f0-9]+$", description="Docker container ID (read only)"
)
@@ -189,7 +189,6 @@ class DynamipsUpdate(DynamipsBase):
class Dynamips(DynamipsBase):
name: str
node_id: UUID
project_id: UUID
@@ -22,7 +22,6 @@ from ..common import NodeStatus
class EthernetHubPort(BaseModel):
name: str
port_number: int
@@ -55,7 +54,6 @@ class EthernetHubUpdate(EthernetHubBase):
class EthernetHub(EthernetHubBase):
name: str
node_id: UUID
project_id: UUID
@@ -23,14 +23,12 @@ from ..common import NodeStatus
class EthernetSwitchPortType(str, Enum):
access = "access"
dot1q = "dot1q"
qinq = "qinq"
class EthernetSwitchEtherType(str, Enum):
ethertype_8021q = "0x8100"
ethertype_qinq = "0x88A8"
ethertype_8021q9100 = "0x9100"
@@ -38,12 +36,13 @@ class EthernetSwitchEtherType(str, Enum):
class EthernetSwitchPort(BaseModel):
name: str
port_number: int
type: EthernetSwitchPortType = Field(..., description="Port type")
vlan: int = Field(..., ge=1, le=4094, description="VLAN number")
ethertype: Optional[EthernetSwitchEtherType] = Field(EthernetSwitchEtherType.ethertype_8021q, description="QinQ Ethertype")
ethertype: Optional[EthernetSwitchEtherType] = Field(
EthernetSwitchEtherType.ethertype_8021q, description="QinQ Ethertype"
)
@model_validator(mode="after")
def check_ethertype(self) -> "EthernetSwitchPort":
@@ -92,7 +91,6 @@ class EthernetSwitchUpdate(EthernetSwitchBase):
class EthernetSwitch(EthernetSwitchBase):
name: str
node_id: UUID
project_id: UUID
@@ -50,6 +50,5 @@ class FrameRelaySwitchUpdate(FrameRelaySwitchBase):
class FrameRelaySwitch(FrameRelaySwitchBase):
project_id: UUID
status: Optional[NodeStatus] = None
-2
View File
@@ -66,7 +66,6 @@ class IOUUpdate(IOUBase):
class IOU(IOUBase):
project_id: UUID = Field(..., description="Project ID")
node_directory: str = Field(..., description="Path to the node working directory (read only)")
command_line: str = Field(..., description="Last command line used to start IOU (read only)")
@@ -74,6 +73,5 @@ class IOU(IOUBase):
class IOUStart(BaseModel):
iourc_content: Optional[str] = Field(None, description="Content of the iourc file")
license_check: Optional[bool] = Field(None, description="Whether the IOU license should be checked")
-2
View File
@@ -23,7 +23,6 @@ from ..common import NodeStatus
class HostInterfaceType(str, Enum):
ethernet = "ethernet"
tap = "tap"
@@ -115,7 +114,6 @@ class NATUpdate(NATBase):
class NAT(NATBase):
project_id: UUID
node_id: UUID
ports_mapping: List[Union[EthernetPort, TAPPort, UDPPort]]
-3
View File
@@ -21,7 +21,6 @@ from enum import Enum
class UDPNIOType(str, Enum):
udp = "nio_udp"
@@ -40,7 +39,6 @@ class UDPNIO(BaseModel):
class EthernetNIOType(str, Enum):
ethernet = "nio_ethernet"
@@ -54,7 +52,6 @@ class EthernetNIO(BaseModel):
class TAPNIOType(str, Enum):
tap = "nio_tap"
-4
View File
@@ -23,7 +23,6 @@ from ..common import NodeStatus, CustomAdapter
class QemuPlatform(str, Enum):
aarch64 = "aarch64"
alpha = "alpha"
arm = "arm"
@@ -94,7 +93,6 @@ class QemuOnCloseAction(str, Enum):
class QemuProcessPriority(str, Enum):
realtime = "realtime"
very_high = "very high"
high = "high"
@@ -236,7 +234,6 @@ class QemuUpdate(QemuBase):
class Qemu(QemuBase):
project_id: UUID = Field(..., description="Project ID")
node_directory: str = Field(..., description="Path to the node working directory (read only)")
command_line: str = Field(..., description="Last command line used to start IOU (read only)")
@@ -244,6 +241,5 @@ class Qemu(QemuBase):
class QemuBinaryPath(BaseModel):
path: str
version: str
@@ -43,7 +43,6 @@ class VirtualBoxOnCloseAction(str, Enum):
class VirtualBoxAdapterType(str, Enum):
pcnet_pci_ii = ("PCnet-PCI II (Am79C970A)",)
pcnet_fast_iii = ("PCNet-FAST III (Am79C973)",)
intel_pro_1000_mt_desktop = ("Intel PRO/1000 MT Desktop (82540EM)",)
@@ -92,7 +91,6 @@ class VirtualBoxUpdate(VirtualBoxBase):
class VirtualBox(VirtualBoxBase):
project_id: UUID = Field(..., description="Project ID")
node_directory: Optional[str] = Field(None, description="Path to the node working directory (read only)")
status: NodeStatus = Field(..., description="Container status (read only)")
@@ -97,7 +97,6 @@ class VMwareUpdate(VMwareBase):
class VMware(VMwareBase):
project_id: UUID = Field(..., description="Project ID")
node_directory: Optional[str] = Field(None, description="Path to the node working directory (read only)")
status: NodeStatus = Field(..., description="Container status (read only)")
-1
View File
@@ -62,7 +62,6 @@ class VPCSUpdate(VPCSBase):
class VPCS(VPCSBase):
project_id: UUID = Field(..., description="Project ID")
node_directory: str = Field(..., description="Path to the node working directory (read only)")
status: NodeStatus = Field(..., description="Container status (read only)")
+92 -88
View File
@@ -17,96 +17,86 @@
import socket
from enum import Enum
from pydantic import (
ConfigDict,
BaseModel,
Field,
SecretStr,
FilePath,
DirectoryPath,
field_validator,
model_validator
)
from pydantic import ConfigDict, BaseModel, Field, SecretStr, FilePath, DirectoryPath, field_validator, model_validator
from typing import List, Optional
class ControllerSettings(BaseModel):
jwt_secret_key: Optional[str] = Field(
None,
description="Secret key used to sign the JWT authentication tokens "
"(normally managed via the secrets directory, not the configuration file)")
"(normally managed via the secrets directory, not the configuration file)",
)
jwt_algorithm: str = Field("HS256", description="Algorithm used to sign the JWT tokens")
jwt_access_token_expire_minutes: int = Field(
1440, description="Lifetime of the JWT access tokens in minutes (24 hours by default)")
1440, description="Lifetime of the JWT access tokens in minutes (24 hours by default)"
)
jwt_refresh_token_expire_minutes: int = Field(
43200, description="Lifetime of the JWT refresh tokens in minutes (30 days by default)")
43200, description="Lifetime of the JWT refresh tokens in minutes (30 days by default)"
)
default_admin_username: str = Field(
"admin",
description="Username of the super admin account seeded when the controller database is created; "
"changing it has no effect until the database is re-created (which resets the account)")
"changing it has no effect until the database is re-created (which resets the account)",
)
default_admin_password: SecretStr = Field(
SecretStr("admin"),
description="Password of the super admin account seeded when the controller database is created; "
"changing it has no effect until the database is re-created (which resets the account)")
"changing it has no effect until the database is re-created (which resets the account)",
)
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class VPCSSettings(BaseModel):
vpcs_path: str = Field("vpcs", description="VPCS executable location, default: search in PATH")
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class DynamipsSettings(BaseModel):
allocate_aux_console_ports: bool = Field(
False, description="Allocate auxiliary console ports on IOS routers")
allocate_aux_console_ports: bool = Field(False, description="Allocate auxiliary console ports on IOS routers")
mmap_support: bool = Field(
True, description="Use memory-mapped flash files (mmap) to lower the memory usage of routers")
True, description="Use memory-mapped flash files (mmap) to lower the memory usage of routers"
)
dynamips_path: str = Field("dynamips", description="Dynamips executable location, default: search in PATH")
sparse_memory_support: bool = Field(
True, description="Use sparse memory allocation to lower the memory usage of routers")
True, description="Use sparse memory allocation to lower the memory usage of routers"
)
ghost_ios_support: bool = Field(
True, description="Enable Ghost IOS support to share memory between identical IOS images")
True, description="Enable Ghost IOS support to share memory between identical IOS images"
)
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class IOUSettings(BaseModel):
iourc_path: Optional[str] = Field(
None, description="Path of your .iourc file, the file is searched in $HOME/.iourc if not provided")
None, description="Path of your .iourc file, the file is searched in $HOME/.iourc if not provided"
)
license_check: bool = Field(
True,
description="Validate the iourc license file (if disabled, IOU will not start and no errors "
"will be shown when the license is invalid)")
"will be shown when the license is invalid)",
)
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class QemuSettings(BaseModel):
enable_monitor: bool = Field(
True, description="Use the Qemu monitor feature to communicate with Qemu VMs")
enable_monitor: bool = Field(True, description="Use the Qemu monitor feature to communicate with Qemu VMs")
monitor_host: str = Field("127.0.0.1", description="IP used to listen for the monitor")
enable_hardware_acceleration: bool = Field(
True, description="Enable hardware acceleration (KVM)")
enable_hardware_acceleration: bool = Field(True, description="Enable hardware acceleration (KVM)")
require_hardware_acceleration: bool = Field(
False, description="Require hardware acceleration in order to start VMs")
allow_unsafe_options: bool = Field(
False, description="Allow unsafe additional command line options")
ovmf_firmware_dir: str = Field(
"/usr/share/OVMF", description="Path to the OVMF firmware directory")
False, description="Require hardware acceleration in order to start VMs"
)
allow_unsafe_options: bool = Field(False, description="Allow unsafe additional command line options")
ovmf_firmware_dir: str = Field("/usr/share/OVMF", description="Path to the OVMF firmware directory")
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class VirtualBoxSettings(BaseModel):
vboxmanage_path: Optional[str] = None
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
class VMwareSettings(BaseModel):
vmrun_path: Optional[str] = None
vmnet_start_range: int = Field(2, ge=1, le=255)
vmnet_end_range: int = Field(255, ge=1, le=255) # should be limited to 19 on Windows
@@ -121,15 +111,15 @@ class VMwareSettings(BaseModel):
class WebWiresharkSettings(BaseModel):
enabled: bool = Field(
True, description="Enable the Web Wireshark feature (container-based Wireshark in the browser)")
image: str = Field(
"gns3/web-wireshark:latest", description="Docker image for the Web Wireshark containers")
True, description="Enable the Web Wireshark feature (container-based Wireshark in the browser)"
)
image: str = Field("gns3/web-wireshark:latest", description="Docker image for the Web Wireshark containers")
network_subnet: str = Field(
"172.31.0.0/22",
description="Docker network subnet for the Web Wireshark containers (change it if it conflicts "
"with your existing network)")
"with your existing network)",
)
memory: str = Field("2g", description='Memory limit per container (e.g. "512m", "2g")')
cpus: float = Field(1.0, description="CPU cores per container (e.g. 1.0, 2.0)")
pids_limit: int = Field(1000, description="Process limit per container")
@@ -137,13 +127,11 @@ class WebWiresharkSettings(BaseModel):
class ServerProtocol(str, Enum):
http = "http"
https = "https"
class UbridgeControlTransport(str, Enum):
# TCP control channel: -H host:port. ubridge now binds loopback by default,
# so this is reachable only locally. Retained for backward compatibility.
tcp = "tcp"
@@ -153,7 +141,6 @@ class UbridgeControlTransport(str, Enum):
class BuiltinSymbolTheme(str, Enum):
classic = "Classic"
affinity_square_blue = "Affinity-square-blue"
affinity_square_red = "Affinity-square-red"
@@ -164,20 +151,20 @@ class BuiltinSymbolTheme(str, Enum):
class ServerSettings(BaseModel):
local: bool = Field(
False,
description="Local server mode, set by the --local command line argument (not meant to be set by hand)")
False, description="Local server mode, set by the --local command line argument (not meant to be set by hand)"
)
enable_http_auth: bool = Field(True, description="Enable compute HTTP authentication")
name: str = Field(
f"{socket.gethostname()} (controller)",
description="Server name, default is what is returned by socket.gethostname()")
protocol: ServerProtocol = Field(
ServerProtocol.http, description="Protocol used by the server: http or https")
description="Server name, default is what is returned by socket.gethostname()",
)
protocol: ServerProtocol = Field(ServerProtocol.http, description="Protocol used by the server: http or https")
host: str = Field("0.0.0.0", description="IP address where the server listens for connections")
port: int = Field(3080, gt=0, le=65535, description="HTTP port used to control the server")
secrets_dir: Optional[DirectoryPath] = Field(
None, description="Directory where secrets are stored (e.g. the JWT secret key)")
None, description="Directory where secrets are stored (e.g. the JWT secret key)"
)
certfile: Optional[FilePath] = Field(None, description="SSL certificate file, requires enable_ssl")
certkey: Optional[FilePath] = Field(None, description="SSL key file, requires enable_ssl")
enable_ssl: bool = Field(False, description="Enable SSL encryption")
@@ -189,80 +176,98 @@ class ServerSettings(BaseModel):
resources_path: Optional[str] = Field(
None,
description="Path where files like built-in appliances and Docker resources are stored "
"(defaults to the local user data directory)")
"(defaults to the local user data directory)",
)
default_symbol_theme: BuiltinSymbolTheme = Field(
BuiltinSymbolTheme.affinity_square_blue,
description='Default symbol theme, e.g. "Classic" or "Affinity-square-blue"')
allow_raw_images: bool = Field(
True, description="Allow raw images to be uploaded to the server")
auto_discover_images: bool = Field(
True, description="Automatically discover images in the images directory")
report_errors: bool = Field(
True, description="Automatically send crash reports to the GNS3 team")
description='Default symbol theme, e.g. "Classic" or "Affinity-square-blue"',
)
allow_raw_images: bool = Field(True, description="Allow raw images to be uploaded to the server")
auto_discover_images: bool = Field(True, description="Automatically discover images in the images directory")
report_errors: bool = Field(True, description="Automatically send crash reports to the GNS3 team")
additional_images_paths: List[str] = Field(
default_factory=list,
description="Additional paths to look for images (semicolon-separated in the configuration file)")
description="Additional paths to look for images (semicolon-separated in the configuration file)",
)
console_start_port_range: int = Field(
5000, gt=0, le=65535, description="First console port of the range allocated to devices")
5000, gt=0, le=65535, description="First console port of the range allocated to devices"
)
console_end_port_range: int = Field(
10000, gt=0, le=65535, description="Last console port of the range allocated to devices")
10000, gt=0, le=65535, description="Last console port of the range allocated to devices"
)
vnc_console_start_port_range: int = Field(
5900, ge=5900, le=65535, description="First VNC console port of the range allocated to devices")
5900, ge=5900, le=65535, description="First VNC console port of the range allocated to devices"
)
vnc_console_end_port_range: int = Field(
10000, ge=5900, le=65535, description="Last VNC console port of the range allocated to devices")
10000, ge=5900, le=65535, description="Last VNC console port of the range allocated to devices"
)
udp_start_port_range: int = Field(
10000, gt=0, le=65535,
description="First UDP port of the range allocated for inter-device communication (two ports per link)")
10000,
gt=0,
le=65535,
description="First UDP port of the range allocated for inter-device communication (two ports per link)",
)
udp_end_port_range: int = Field(
30000, gt=0, le=65535,
description="Last UDP port of the range allocated for inter-device communication (two ports per link)")
30000,
gt=0,
le=65535,
description="Last UDP port of the range allocated for inter-device communication (two ports per link)",
)
ubridge_path: str = Field("ubridge", description="uBridge executable location, default: search in PATH")
ubridge_control_transport: UbridgeControlTransport = Field(
UbridgeControlTransport.unix,
description='uBridge control channel transport: "unix" (AF_UNIX + SO_PEERCRED, recommended '
'on Linux) or "tcp" (loopback, kept for backward compatibility)')
'on Linux) or "tcp" (loopback, kept for backward compatibility)',
)
marker_listen_host: str = Field(
"127.0.0.1",
description="Marker (traffic-insight) UDP sink listen host: one listener per compute process "
"receives uBridge MARK signals from every uBridge on this host")
"receives uBridge MARK signals from every uBridge on this host",
)
marker_listen_port: int = Field(
3070, ge=0, le=65535,
description="Marker UDP sink listen port (0 lets the operating system choose a free port)")
compute_username: str = Field(
"gns3", description='Username for compute HTTP authentication, "gns3" is the default')
3070, ge=0, le=65535, description="Marker UDP sink listen port (0 lets the operating system choose a free port)"
)
compute_username: str = Field("gns3", description='Username for compute HTTP authentication, "gns3" is the default')
compute_password: SecretStr = Field(
SecretStr(""),
description="Password for compute HTTP authentication, a randomly generated password is used if not set")
description="Password for compute HTTP authentication, a randomly generated password is used if not set",
)
allowed_interfaces: List[str] = Field(
default_factory=list,
description="Only allow these interfaces to be used by GNS3, for the Cloud node for example "
"(comma-separated; do not forget virbr0 for the NAT node to work)")
"(comma-separated; do not forget virbr0 for the NAT node to work)",
)
default_nat_interface: Optional[str] = Field(
None, description="Interface used by the NAT node, default is virbr0 on Linux (requires libvirt)")
None, description="Interface used by the NAT node, default is virbr0 on Linux (requires libvirt)"
)
allow_remote_console: bool = Field(
False,
description="Allow console connections from remote machines "
"(console ports only accept local connections by default)")
"(console ports only accept local connections by default)",
)
enable_builtin_templates: bool = Field(True, description="Enable the built-in templates")
install_builtin_appliances: bool = Field(True, description="Install the built-in appliances")
skills_repo_url: str = Field(
"https://github.com/gns3/gns3-skills.git",
description="Git repository URL for the external GNS3 Copilot skills "
"(injection skills, prompts and device skills)")
"(injection skills, prompts and device skills)",
)
skills_repo_branch: str = Field("main", description="Git branch of the skills repository")
skills_auto_update: bool = Field(
True, description="Automatically pull updates from the skills repository when reloading")
True, description="Automatically pull updates from the skills repository when reloading"
)
mcp_enable_dns_rebinding_protection: bool = Field(
False,
description="Enable MCP transport DNS rebinding protection "
"(allowed hosts and origins must be configured)")
description="Enable MCP transport DNS rebinding protection (allowed hosts and origins must be configured)",
)
mcp_allowed_hosts: list[str] = Field(
default_factory=list,
description='Allowed hosts for MCP connections, only "host:*" port wildcards are supported '
'(e.g. "127.0.0.1:*")')
'(e.g. "127.0.0.1:*")',
)
mcp_allowed_origins: list[str] = Field(
default_factory=list,
description='Allowed origins for MCP connections (e.g. "http://localhost:*")')
default_factory=list, description='Allowed origins for MCP connections (e.g. "http://localhost:*")'
)
model_config = ConfigDict(validate_assignment=True, str_strip_whitespace=True)
@@ -325,7 +330,6 @@ class ServerSettings(BaseModel):
class ServerConfig(BaseModel):
Server: ServerSettings = ServerSettings()
Controller: ControllerSettings = ControllerSettings()
VPCS: VPCSSettings = VPCSSettings()
File diff suppressed because it is too large. Load diff
-1
View File
@@ -20,6 +20,5 @@ from pydantic import BaseModel
class DateTimeModelMixin(BaseModel):
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
+9 -9
View File
@@ -40,7 +40,7 @@ class ChatRequest(BaseModel):
None,
description="LLM temperature parameter (NOTE: currently not used. "
"Temperature is loaded from user's LLM config in database. "
"Reserved for future runtime override support.)"
"Reserved for future runtime override support.)",
)
mode: Literal["text"] = Field(default="text", description="Interaction mode")
@@ -49,14 +49,14 @@ class ChatResponse(BaseModel):
"""Chat streaming response model."""
type: Literal[
"content", # AI text content
"tool_call", # Tool call request
"tool_start", # Tool execution started
"tool_end", # Tool execution completed
"error", # Error message
"done", # Stream ended
"heartbeat", # Keep-alive signal
"abort" # Stream aborted
"content", # AI text content
"tool_call", # Tool call request
"tool_start", # Tool execution started
"tool_end", # Tool execution completed
"error", # Error message
"done", # Stream ended
"heartbeat", # Keep-alive signal
"abort", # Stream aborted
] = Field(..., description="Response message type")
content: Optional[str] = Field(None, description="Text content (for type=content)")
message_id: Optional[str] = Field(None, description="Message ID")
+19 -27
View File
@@ -16,14 +16,7 @@
import uuid
from pydantic import (
ConfigDict,
BaseModel,
Field,
SecretStr,
field_validator,
model_validator
)
from pydantic import ConfigDict, BaseModel, Field, SecretStr, field_validator, model_validator
from typing import List, Optional, Union, Any
from enum import Enum
@@ -60,27 +53,22 @@ class ComputeCreate(ComputeBase):
"""
compute_id: Union[str, uuid.UUID] = None
model_config = ConfigDict(json_schema_extra={
"example": {
"name": "My compute",
"host": "127.0.0.1",
"port": 3080,
"user": "user",
"password": "password"
model_config = ConfigDict(
json_schema_extra={
"example": {"name": "My compute", "host": "127.0.0.1", "port": 3080, "user": "user", "password": "password"}
}
})
)
@model_validator(mode='before')
@model_validator(mode="before")
@classmethod
def set_default_compute_id_and_name(cls, data: Any) -> Any:
if "compute_id" not in data:
data['compute_id'] = uuid.uuid5(
uuid.NAMESPACE_URL,
f"{data.get('protocol')}://{data.get('host')}:{data.get('port')}"
data["compute_id"] = uuid.uuid5(
uuid.NAMESPACE_URL, f"{data.get('protocol')}://{data.get('host')}:{data.get('port')}"
)
if "name" not in data:
data['name'] = f"{data.get('protocol')}://{data.get('user', '')}@{data.get('host')}:{data.get('port')}"
data["name"] = f"{data.get('protocol')}://{data.get('user', '')}@{data.get('host')}:{data.get('port')}"
return data
@@ -94,12 +82,14 @@ class ComputeUpdate(ComputeBase):
port: Optional[int] = Field(None, gt=0, le=65535)
user: Optional[str] = None
password: Optional[SecretStr] = None
model_config = ConfigDict(json_schema_extra={
"example": {
"host": "10.0.0.1",
"port": 8080,
model_config = ConfigDict(
json_schema_extra={
"example": {
"host": "10.0.0.1",
"port": 8080,
}
}
})
)
class Capabilities(BaseModel):
@@ -165,4 +155,6 @@ class AutoIdlePC(BaseModel):
platform: str = Field(..., description="Cisco platform")
image: str = Field(..., description="Image path")
ram: int = Field(..., description="Amount of RAM in MB")
model_config = ConfigDict(json_schema_extra={"example": {"platform": "c7200", "image": "/path/to/c7200_image.bin", "ram": 256}})
model_config = ConfigDict(
json_schema_extra={"example": {"platform": "c7200", "image": "/path/to/c7200_image.bin", "ram": 256}}
)
-1
View File
@@ -21,7 +21,6 @@ from .base import DateTimeModelMixin
class ImageType(str, Enum):
qemu = "qemu"
ios = "ios"
iou = "iou"
@@ -18,6 +18,5 @@ from pydantic import BaseModel, Field
class IOULicense(BaseModel):
iourc_content: str = Field(..., description="Content of iourc file")
license_check: bool = Field(..., description="Whether the license must be checked or not")
+10 -28
View File
@@ -43,7 +43,6 @@ class LinkType(str, Enum):
class LinkStyle(BaseModel):
color: Optional[str] = None
width: Optional[int] = None
type: Optional[int] = None
@@ -63,50 +62,36 @@ class LinkBase(BaseModel):
link_style: Optional[LinkStyle] = None
filters: Optional[dict] = None
markers: Optional[dict] = Field(
None,
description="Traffic-insight markers on this link: name → {bpf, tag, enabled}"
)
show_filters_icon: Optional[bool] = Field(
True,
description="Show filters icon in Web UI"
None, description="Traffic-insight markers on this link: name → {bpf, tag, enabled}"
)
show_filters_icon: Optional[bool] = Field(True, description="Show filters icon in Web UI")
class LinkCreate(LinkBase):
link_id: UUID = Field(default_factory=uuid4)
nodes: List[LinkNode] = Field(..., min_length=2, max_length=2)
class LinkUpdate(LinkBase):
pass
class Link(LinkBase):
link_id: UUID
project_id: Optional[UUID] = None
link_type: Optional[LinkType] = None
capturing: Optional[bool] = Field(
None,
description="Read only property. True if a capture running on the link"
)
capturing: Optional[bool] = Field(None, description="Read only property. True if a capture running on the link")
capture_file_name: Optional[str] = Field(
None,
description="Read only property. The name of the capture file if a capture is running"
None, description="Read only property. The name of the capture file if a capture is running"
)
capture_file_path: Optional[str] = Field(
None,
description="Read only property. The full path of the capture file if a capture is running"
None, description="Read only property. The full path of the capture file if a capture is running"
)
capture_compute_id: Optional[str] = Field(
None,
description="Read only property. The compute identifier where a capture is running"
None, description="Read only property. The compute identifier where a capture is running"
)
wireshark: Optional[bool] = Field(
False,
description="Read only property. True if a Web Wireshark session is active on the link"
False, description="Read only property. True if a Web Wireshark session is active on the link"
)
@@ -121,6 +106,7 @@ class UDPPortInfo(BaseModel):
rport: int
type: str
class EthernetPortInfo(BaseModel):
"""
Ethernet port information.
@@ -153,7 +139,7 @@ class MarkerCreate(BaseModel):
None,
pattern=r"^[A-Za-z0-9][A-Za-z0-9_.-]*$",
max_length=32,
description='Unique marker name on the link. Auto-generated when absent.',
description="Unique marker name on the link. Auto-generated when absent.",
)
bpf: str
tag: Optional[int] = None
@@ -226,9 +212,7 @@ class MarkerUpdate(BaseModel):
description="Direction filter; 'both' or an explicit null clears it to both. Omit to keep.",
)
color: Optional[str] = Field(None, description="Hex color render hint, e.g. '#ff5722'")
highlight_duration: Optional[int] = Field(
None, ge=1, description="UI highlight duration in ms; null = UI default"
)
highlight_duration: Optional[int] = Field(None, ge=1, description="UI highlight duration in ms; null = UI default")
enabled: Optional[bool] = Field(None, description="Toggle the marker on/off (instant).")
@field_validator("direction", mode="before")
@@ -288,5 +272,3 @@ class MarkerDefinitionCreate(BaseModel):
@classmethod
def _both_to_none(cls, v):
return None if v == "both" else v
@@ -22,7 +22,7 @@ from .base import DateTimeModelMixin
# Valid model types
ModelType = Literal['text', 'vision', 'stt', 'tts', 'multimodal', 'embedding', 'reranking', 'other']
ModelType = Literal["text", "vision", "stt", "tts", "multimodal", "embedding", "reranking", "other"]
# Core model config schema (stored in config JSONB field)
@@ -51,8 +51,7 @@ class LLMModelConfigData(BaseModel):
"balanced", description="Context trimming strategy: conservative (60%), balanced (75%), aggressive (85%)"
)
copilot_mode: Optional[str] = Field(
None,
description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
None, description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
)
# Allow extra fields for extensibility
@@ -81,8 +80,7 @@ class LLMModelConfigCreate(BaseModel):
"balanced", description="Context trimming strategy"
)
copilot_mode: Optional[str] = Field(
None,
description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
None, description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
)
# Allow extra config fields
@@ -112,14 +110,13 @@ class LLMModelConfigUpdate(BaseModel):
None, description="Context trimming strategy"
)
copilot_mode: Optional[str] = Field(
None,
description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
None, description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
)
# Allow extra config fields
model_config = ConfigDict(extra="allow")
@field_validator('max_tokens', mode='before')
@field_validator("max_tokens", mode="before")
@classmethod
def validate_max_tokens(cls, v):
"""Handle string 'null' values for max_tokens."""
@@ -150,8 +147,7 @@ class LLMModelConfigDataWithoutSecret(BaseModel):
"balanced", description="Context trimming strategy: conservative (60%), balanced (75%), aggressive (85%)"
)
copilot_mode: Optional[str] = Field(
None,
description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
None, description="GNS3-Copilot mode: 'teaching_assistant' or 'lab_automation_assistant'"
)
# Allow extra fields for extensibility
+4 -6
View File
@@ -157,13 +157,11 @@ class NodeBase(BaseModel):
first_port_name: Optional[str] = Field(None, description="Name of the first port")
custom_adapters: Optional[List[CustomAdapter]] = None
tags: Optional[List[str]] = Field(
default_factory=list,
description="User-defined metadata tags (e.g. 'vendor:cisco' or 'model:7200')"
default_factory=list, description="User-defined metadata tags (e.g. 'vendor:cisco' or 'model:7200')"
)
class NodeCreate(NodeBase):
node_id: UUID = Field(default_factory=uuid4)
@@ -178,9 +176,9 @@ class NodeUpdate(NodeBase):
class Node(NodeBase):
template_id: Optional[UUID] = Field(None,
description="Template UUID from which the node has been created. Read only")
template_id: Optional[UUID] = Field(
None, description="Template UUID from which the node has been created. Read only"
)
project_id: Optional[UUID] = None
node_directory: Optional[str] = Field(None, description="Working directory of the node. Read only")
status: Optional[NodeStatus] = Field(None, description="Node status. Read only")
-3
View File
@@ -23,7 +23,6 @@ from .base import DateTimeModelMixin
class ResourceType(str, Enum):
project = "project"
@@ -47,7 +46,6 @@ class ResourceCreate(ResourceBase):
class Resource(DateTimeModelMixin, ResourceBase):
model_config = ConfigDict(from_attributes=True)
@@ -76,6 +74,5 @@ class ResourcePoolUpdate(ResourcePoolBase):
class ResourcePool(DateTimeModelMixin, ResourcePoolBase):
resource_pool_id: UUID
model_config = ConfigDict(from_attributes=True)
@@ -31,13 +31,11 @@ class ProjectStatus(str, Enum):
class Supplier(BaseModel):
logo: str = Field(..., description="Path to the project supplier logo")
url: Optional[HttpUrl] = Field(None, description="URL to the project supplier site")
class Variable(BaseModel):
name: str = Field(..., description="Variable name")
value: Optional[str] = Field(None, description="Variable value")
@@ -91,7 +89,6 @@ class ProjectUpdate(ProjectBase):
class Project(ProjectBase):
project_id: UUID
name: Optional[str] = None
status: Optional[ProjectStatus] = None
@@ -100,7 +97,6 @@ class Project(ProjectBase):
class ProjectFile(BaseModel):
path: str = Field(..., description="File path")
md5sum: str = Field(..., description="File checksum")
-4
View File
@@ -32,13 +32,11 @@ class PrivilegeBase(BaseModel):
class Privilege(DateTimeModelMixin, PrivilegeBase):
privilege_id: UUID
model_config = ConfigDict(from_attributes=True)
class ACEType(str, Enum):
user = "user"
group = "group"
@@ -75,7 +73,6 @@ class ACEUpdate(ACEBase):
class ACE(DateTimeModelMixin, ACEBase):
ace_id: UUID
model_config = ConfigDict(from_attributes=True)
@@ -106,7 +103,6 @@ class RoleUpdate(RoleBase):
class Role(DateTimeModelMixin, RoleBase):
role_id: UUID
is_builtin: bool
privileges: List[Privilege]
+12 -19
View File
@@ -47,11 +47,9 @@ SECRET_MASK = "**********"
class ServerSettingsResponse(ServerSettings):
# plain strings instead of FilePath/DirectoryPath: paths are validated when
# the settings are loaded or updated, not when echoed back to the client
secrets_dir: Optional[str] = Field(
None, description="Directory where secrets are stored (e.g. the JWT secret key)")
secrets_dir: Optional[str] = Field(None, description="Directory where secrets are stored (e.g. the JWT secret key)")
certfile: Optional[str] = Field(None, description="SSL certificate file, requires enable_ssl")
certkey: Optional[str] = Field(None, description="SSL key file, requires enable_ssl")
# Optional overrides: typed as plain "str = None" in the config schema,
@@ -59,28 +57,30 @@ class ServerSettingsResponse(ServerSettings):
resources_path: Optional[str] = Field(
None,
description="Path where files like built-in appliances and Docker resources are stored "
"(defaults to the local user data directory)")
"(defaults to the local user data directory)",
)
default_nat_interface: Optional[str] = Field(
None, description="Interface used by the NAT node, default is virbr0 on Linux (requires libvirt)")
None, description="Interface used by the NAT node, default is virbr0 on Linux (requires libvirt)"
)
class ControllerSettingsResponse(ControllerSettings):
# never serialized: managed via the secrets directory, not the configuration file
jwt_secret_key: Optional[str] = Field(
default=None, exclude=True,
default=None,
exclude=True,
description="Secret key used to sign the JWT authentication tokens "
"(normally managed via the secrets directory, not the configuration file)")
"(normally managed via the secrets directory, not the configuration file)",
)
class IOUSettingsResponse(IOUSettings):
iourc_path: Optional[str] = Field(
None, description="Path of your .iourc file, the file is searched in $HOME/.iourc if not provided")
None, description="Path of your .iourc file, the file is searched in $HOME/.iourc if not provided"
)
class SettingsResponse(BaseModel):
Server: ServerSettingsResponse
Controller: ControllerSettingsResponse
VPCS: VPCSSettings
@@ -160,14 +160,12 @@ class ControllerSettingsUpdate(BaseModel):
class VPCSSettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
vpcs_path: Optional[str] = None
class DynamipsSettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
allocate_aux_console_ports: Optional[bool] = None
@@ -178,7 +176,6 @@ class DynamipsSettingsUpdate(BaseModel):
class IOUSettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
iourc_path: Optional[str] = None
@@ -186,7 +183,6 @@ class IOUSettingsUpdate(BaseModel):
class QemuSettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
enable_monitor: Optional[bool] = None
@@ -198,7 +194,6 @@ class QemuSettingsUpdate(BaseModel):
class WebWiresharkSettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid", str_strip_whitespace=True)
enabled: Optional[bool] = None
@@ -210,7 +205,6 @@ class WebWiresharkSettingsUpdate(BaseModel):
class SettingsUpdate(BaseModel):
model_config = ConfigDict(extra="forbid")
Server: Optional[ServerSettingsUpdate] = None
@@ -223,8 +217,7 @@ class SettingsUpdate(BaseModel):
class SettingsUpdateResponse(SettingsResponse):
restart_required: List[str] = Field(
default_factory=list,
description="Changed 'Section.option' settings that require a server restart to take effect"
description="Changed 'Section.option' settings that require a server restart to take effect",
)
+1 -1
View File
@@ -28,6 +28,7 @@ class SnapshotBase(BaseModel):
name: str = Field(..., description="Name of the snapshot")
description: Optional[str] = Field(None, description="Description of the snapshot")
class SnapshotCreate(SnapshotBase):
"""
Properties for snapshot creation.
@@ -37,7 +38,6 @@ class SnapshotCreate(SnapshotBase):
class Snapshot(SnapshotBase):
snapshot_id: UUID
project_id: UUID
name: str = Field(..., description="Name of the snapshot")
@@ -43,9 +43,7 @@ class ApplianceMetadata(BaseModel):
model_config = ConfigDict(extra="allow")
appliance_id: Optional[str] = Field(
None, description="ID of the appliance the template was installed from"
)
appliance_id: Optional[str] = Field(None, description="ID of the appliance the template was installed from")
description: Optional[str] = None
vendor_name: Optional[str] = None
vendor_url: Optional[str] = None
@@ -82,12 +80,10 @@ class TemplateBase(BaseModel):
pattern=r"^[a-z0-9_]+$|^$",
)
tags: Optional[List[str]] = Field(
default_factory=list,
description="User-defined metadata tags (e.g. 'vendor:cisco' or 'model:7200')"
default_factory=list, description="User-defined metadata tags (e.g. 'vendor:cisco' or 'model:7200')"
)
appliance_metadata: Optional[ApplianceMetadata] = Field(
None,
description="Metadata inherited from the appliance the template was installed from"
None, description="Metadata inherited from the appliance the template was installed from"
)
@@ -106,7 +102,6 @@ class TemplateUpdate(TemplateBase):
class Template(DateTimeModelMixin, TemplateBase):
template_id: UUID
name: str
category: Category
@@ -117,7 +112,6 @@ class Template(DateTimeModelMixin, TemplateBase):
class TemplateUsage(BaseModel):
x: int
y: int
name: Optional[str] = Field(None, description="Use this name to create a new node")
@@ -16,19 +16,13 @@
from . import Category, TemplateBase
from gns3server.schemas.compute.cloud_nodes import (
EthernetPort,
TAPPort,
UDPPort,
CloudConsoleType
)
from gns3server.schemas.compute.cloud_nodes import EthernetPort, TAPPort, UDPPort, CloudConsoleType
from pydantic import Field
from typing import Optional, Union, List
class CloudTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "Cloud{0}"
symbol: Optional[str] = "cloud"
@@ -40,5 +34,4 @@ class CloudTemplate(TemplateBase):
class CloudTemplateUpdate(CloudTemplate):
pass
@@ -23,13 +23,14 @@ from typing import Optional, List
class DockerTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "{name}-{0}"
symbol: Optional[str] = "docker_guest"
image: str = Field(..., description="Docker image name")
adapters: Optional[int] = Field(1, ge=0, le=100, description="Number of adapters")
mac_address: Optional[str] = Field("", description="Base MAC address", pattern="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$|^$")
mac_address: Optional[str] = Field(
"", description="Base MAC address", pattern="^([0-9a-fA-F]{2}[:]){5}([0-9a-fA-F]{2})$|^$"
)
start_command: Optional[str] = Field("", description="Docker CMD entry")
environment: Optional[str] = Field("", description="Docker environment variables")
console_type: Optional[ConsoleType] = Field(ConsoleType.telnet, description="Console type")
@@ -49,12 +50,13 @@ class DockerTemplate(TemplateBase):
)
extra_hosts: Optional[str] = Field("", description="Docker extra hosts (added to /etc/hosts)")
extra_volumes: Optional[List] = Field([], description="Additional directories to make persistent")
extra_configs: Optional[List[ExtraConfig]] = Field(default_factory=list, description="Configuration files injected into the container (bind-mounted read-only)")
extra_configs: Optional[List[ExtraConfig]] = Field(
default_factory=list, description="Configuration files injected into the container (bind-mounted read-only)"
)
memory: Optional[int] = Field(0, ge=0, description="Maximum amount of memory the container can use in MB")
cpus: Optional[float] = Field(0, ge=0, description="Maximum amount of CPU resources the container can use")
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
class DockerTemplateUpdate(DockerTemplate):
image: Optional[str] = Field(None, description="Docker image name")
image: Optional[str] = Field(None, description="Docker image name")
@@ -31,7 +31,6 @@ from enum import Enum
class DynamipsTemplate(TemplateBase):
category: Optional[Category] = Category.router
default_name_format: Optional[str] = "R{0}"
symbol: Optional[str] = "router"
@@ -69,7 +68,6 @@ class DynamipsTemplate(TemplateBase):
class C7200DynamipsTemplate(DynamipsTemplate):
ram: Optional[int] = Field(512, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(512, gt=0, description="Amount of NVRAM in KB")
npe: Optional[DynamipsNPE] = Field(DynamipsNPE.npe_400, description="NPE model")
@@ -78,13 +76,11 @@ class C7200DynamipsTemplate(DynamipsTemplate):
class C7200DynamipsTemplateUpdate(C7200DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C3725DynamipsTemplate(DynamipsTemplate):
ram: Optional[int] = Field(128, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(256, gt=0, description="Amount of NVRAM in KB")
iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage")
@@ -92,13 +88,11 @@ class C3725DynamipsTemplate(DynamipsTemplate):
class C3725DynamipsTemplateUpdate(C3725DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C3745DynamipsTemplate(DynamipsTemplate):
ram: Optional[int] = Field(256, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(256, gt=0, description="Amount of NVRAM in KB")
iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage")
@@ -106,20 +100,17 @@ class C3745DynamipsTemplate(DynamipsTemplate):
class C3745DynamipsTemplateUpdate(C3745DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C3600ChassisType(str, Enum):
chassis_3620 = "3620"
chassis_3640 = "3640"
chassis_3660 = "3660"
class C3600DynamipsTemplate(DynamipsTemplate):
chassis: Optional[C3600ChassisType] = Field("c3660", description="Chassis type")
ram: Optional[int] = Field(192, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(128, gt=0, description="Amount of NVRAM in KB")
@@ -128,13 +119,11 @@ class C3600DynamipsTemplate(DynamipsTemplate):
class C3600DynamipsTemplateUpdate(C3600DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C2691DynamipsTemplate(DynamipsTemplate):
ram: Optional[int] = Field(192, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(256, gt=0, description="Amount of NVRAM in KB")
iomem: Optional[int] = Field(5, ge=0, le=100, description="I/O memory percentage")
@@ -142,13 +131,11 @@ class C2691DynamipsTemplate(DynamipsTemplate):
class C2691DynamipsTemplateUpdate(C2691DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C2600ChassisType(str, Enum):
chassis_2610 = "2610"
chassis_2620 = "2620"
chassis_2610xm = "2610XM"
@@ -161,7 +148,6 @@ class C2600ChassisType(str, Enum):
class C2600DynamipsTemplate(DynamipsTemplate):
chassis: Optional[C2600ChassisType] = Field("2651XM", description="Chassis type")
ram: Optional[int] = Field(160, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(128, gt=0, description="Amount of NVRAM in KB")
@@ -170,13 +156,11 @@ class C2600DynamipsTemplate(DynamipsTemplate):
class C2600DynamipsTemplateUpdate(C2600DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
class C1700ChassisType(str, Enum):
chassis_1720 = "1720"
chassis_1721 = "1721"
chassis_1750 = "1750"
@@ -185,7 +169,6 @@ class C1700ChassisType(str, Enum):
class C1700DynamipsTemplate(DynamipsTemplate):
chassis: Optional[C1700ChassisType] = Field("1760", description="Chassis type")
ram: Optional[int] = Field(160, gt=0, description="Amount of RAM in MB")
nvram: Optional[int] = Field(128, gt=0, description="Amount of NVRAM in KB")
@@ -194,6 +177,5 @@ class C1700DynamipsTemplate(DynamipsTemplate):
class C1700DynamipsTemplateUpdate(C1700DynamipsTemplate):
platform: Optional[DynamipsPlatform] = Field(None, description="Cisco router platform")
image: Optional[str] = Field(None, description="Path to the IOS image")
@@ -34,7 +34,6 @@ DEFAULT_PORTS = [
class EthernetHubTemplate(TemplateBase):
category: Optional[Category] = Category.switch
default_name_format: Optional[str] = "Hub{0}"
symbol: Optional[str] = "hub"
@@ -42,5 +41,4 @@ class EthernetHubTemplate(TemplateBase):
class EthernetHubTemplateUpdate(EthernetHubTemplate):
pass
@@ -44,7 +44,6 @@ class ConsoleType(str, Enum):
class EthernetSwitchTemplate(TemplateBase):
category: Optional[Category] = Category.switch
default_name_format: Optional[str] = "Switch{0}"
symbol: Optional[str] = "ethernet_switch"
@@ -53,5 +52,4 @@ class EthernetSwitchTemplate(TemplateBase):
class EthernetSwitchTemplateUpdate(EthernetSwitchTemplate):
pass
@@ -23,7 +23,6 @@ from typing import Optional
class IOUTemplate(TemplateBase):
category: Optional[Category] = Category.router
default_name_format: Optional[str] = "IOU{0}"
symbol: Optional[str] = "multilayer_switch"
@@ -46,5 +45,4 @@ class IOUTemplate(TemplateBase):
class IOUTemplateUpdate(IOUTemplate):
path: Optional[str] = Field(None, description="Path of IOU executable")
@@ -32,7 +32,6 @@ from typing import Optional, List
class QemuTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "{name}-{0}"
symbol: Optional[str] = "qemu_guest"
@@ -62,13 +61,21 @@ class QemuTemplate(TemplateBase):
aux_type: Optional[QemuConsoleType] = Field(QemuConsoleType.none, description="Auxiliary console type")
boot_priority: Optional[QemuBootPriority] = Field(QemuBootPriority.c, description="QEMU boot priority")
hda_disk_image: Optional[str] = Field("", description="QEMU hda disk image path")
hda_disk_interface: Optional[QemuDiskInterfaceType] = Field(QemuDiskInterfaceType.none, description="QEMU hda interface")
hda_disk_interface: Optional[QemuDiskInterfaceType] = Field(
QemuDiskInterfaceType.none, description="QEMU hda interface"
)
hdb_disk_image: Optional[str] = Field("", description="QEMU hdb disk image path")
hdb_disk_interface: Optional[QemuDiskInterfaceType] = Field(QemuDiskInterfaceType.none, description="QEMU hdb interface")
hdb_disk_interface: Optional[QemuDiskInterfaceType] = Field(
QemuDiskInterfaceType.none, description="QEMU hdb interface"
)
hdc_disk_image: Optional[str] = Field("", description="QEMU hdc disk image path")
hdc_disk_interface: Optional[QemuDiskInterfaceType] = Field(QemuDiskInterfaceType.none, description="QEMU hdc interface")
hdc_disk_interface: Optional[QemuDiskInterfaceType] = Field(
QemuDiskInterfaceType.none, description="QEMU hdc interface"
)
hdd_disk_image: Optional[str] = Field("", description="QEMU hdd disk image path")
hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field(QemuDiskInterfaceType.none, description="QEMU hdd interface")
hdd_disk_interface: Optional[QemuDiskInterfaceType] = Field(
QemuDiskInterfaceType.none, description="QEMU hdd interface"
)
cdrom_image: Optional[str] = Field("", description="QEMU cdrom image path")
initrd: Optional[str] = Field("", description="QEMU initrd path")
kernel_image: Optional[str] = Field("", description="QEMU kernel image path")
@@ -82,13 +89,16 @@ class QemuTemplate(TemplateBase):
)
tpm: Optional[bool] = Field(False, description="Enable Trusted Platform Module (TPM)")
uefi: Optional[bool] = Field(False, description="Enable UEFI boot mode")
on_close: Optional[QemuOnCloseAction] = Field(QemuOnCloseAction.power_off, description="Action to execute on the VM is closed")
on_close: Optional[QemuOnCloseAction] = Field(
QemuOnCloseAction.power_off, description="Action to execute on the VM is closed"
)
cpu_throttling: Optional[int] = Field(0, ge=0, le=800, description="Percentage of CPU allowed for QEMU")
process_priority: Optional[QemuProcessPriority] = Field(QemuProcessPriority.normal, description="Process priority for QEMU")
process_priority: Optional[QemuProcessPriority] = Field(
QemuProcessPriority.normal, description="Process priority for QEMU"
)
options: Optional[str] = Field("", description="Additional QEMU options")
custom_adapters: Optional[List[CustomAdapter]] = Field(default_factory=list, description="Custom adapters")
class QemuTemplateUpdate(QemuTemplate):
pass
@@ -19,7 +19,7 @@ from gns3server.schemas.compute.virtualbox_nodes import (
VirtualBoxConsoleType,
VirtualBoxAdapterType,
VirtualBoxOnCloseAction,
CustomAdapter
CustomAdapter,
)
from pydantic import Field
@@ -27,7 +27,6 @@ from typing import Optional, List
class VirtualBoxTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "{name}-{0}"
symbol: Optional[str] = "vbox_guest"
@@ -38,7 +37,8 @@ class VirtualBoxTemplate(TemplateBase):
1, ge=0, le=36, description="Number of adapters"
) # 36 is the maximum given by the ICH9 chipset in VirtualBox
use_any_adapter: Optional[bool] = Field(False, description="Allow GNS3 to use any VirtualBox adapter")
adapter_type: Optional[VirtualBoxAdapterType] = Field(VirtualBoxAdapterType.intel_pro_1000_mt_desktop, description="VirtualBox adapter type"
adapter_type: Optional[VirtualBoxAdapterType] = Field(
VirtualBoxAdapterType.intel_pro_1000_mt_desktop, description="VirtualBox adapter type"
)
first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0")
port_name_format: Optional[str] = Field(
@@ -60,5 +60,4 @@ class VirtualBoxTemplate(TemplateBase):
class VirtualBoxTemplateUpdate(VirtualBoxTemplate):
vmname: Optional[str] = Field(None, description="VirtualBox VM name (in VirtualBox itself)")
@@ -20,7 +20,7 @@ from gns3server.schemas.compute.vmware_nodes import (
VMwareConsoleType,
VMwareAdapterType,
VMwareOnCloseAction,
CustomAdapter
CustomAdapter,
)
from pydantic import Field
@@ -28,7 +28,6 @@ from typing import Optional, List
class VMwareTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "{name}-{0}"
symbol: Optional[str] = "vmware_guest"
@@ -48,7 +47,9 @@ class VMwareTemplate(TemplateBase):
adapter_type: Optional[VMwareAdapterType] = Field(VMwareAdapterType.e1000, description="VMware adapter type")
use_any_adapter: Optional[bool] = Field(False, description="Allow GNS3 to use any VMware adapter")
headless: Optional[bool] = Field(False, description="Headless mode")
on_close: Optional[VMwareOnCloseAction] = Field(VMwareOnCloseAction.power_off, description="Action to execute on the VM is closed")
on_close: Optional[VMwareOnCloseAction] = Field(
VMwareOnCloseAction.power_off, description="Action to execute on the VM is closed"
)
console_type: Optional[VMwareConsoleType] = Field(VMwareConsoleType.none, description="Console type")
console_auto_start: Optional[bool] = Field(
False, description="Automatically start the console when the node has started"
@@ -57,5 +58,4 @@ class VMwareTemplate(TemplateBase):
class VMwareTemplateUpdate(VMwareTemplate):
vmx_path: Optional[str] = Field(None, description="Path to the vmx file")
@@ -23,7 +23,6 @@ from typing import Optional
class VPCSTemplate(TemplateBase):
category: Optional[Category] = Category.guest
default_name_format: Optional[str] = "PC{0}"
symbol: Optional[str] = "vpcs_guest"
@@ -35,5 +34,4 @@ class VPCSTemplate(TemplateBase):
class VPCSTemplateUpdate(VPCSTemplate):
pass
-2
View File
@@ -19,14 +19,12 @@ from pydantic import BaseModel
class Token(BaseModel):
access_token: str
token_type: str
refresh_token: Optional[str] = None
class TokenData(BaseModel):
username: Optional[str] = None
token_version: int = 0
token_use: str = "access"
@@ -33,12 +33,10 @@ from uuid import UUID
class TopologyType(str, Enum):
topology = "topology"
class TopologyContent(BaseModel):
computes: List[Compute] = Field(..., description="List of computes")
drawings: List[Drawing] = Field(..., description="List of drawings")
links: List[Link] = Field(..., description="List of links")
@@ -46,7 +44,6 @@ class TopologyContent(BaseModel):
class Topology(BaseModel):
project_id: UUID = Field(..., description="Project UUID")
type: TopologyType = Field(..., description="Type of file. It's always topology")
revision: int = Field(..., description="Version of the .gns3 specification")
-3
View File
@@ -61,7 +61,6 @@ class LoggedInUserUpdate(BaseModel):
class User(DateTimeModelMixin, UserBase):
user_id: UUID
last_login: Optional[datetime] = None
is_superadmin: bool = False
@@ -93,13 +92,11 @@ class UserGroupUpdate(UserGroupBase):
class UserGroup(DateTimeModelMixin, UserGroupBase):
user_group_id: UUID
is_builtin: bool
model_config = ConfigDict(from_attributes=True)
class Credentials(BaseModel):
username: str
password: str
-3
View File
@@ -78,7 +78,6 @@ class QemuDiskImageAdapterType(str, Enum):
class QemuDiskImageBase(BaseModel):
format: QemuDiskImageFormat = Field(..., description="Image format type")
size: int = Field(..., description="Image size in Megabytes")
preallocation: Optional[QemuDiskImagePreallocation] = None
@@ -92,12 +91,10 @@ class QemuDiskImageBase(BaseModel):
class QemuDiskImageCreate(QemuDiskImageBase):
pass
class QemuDiskImageUpdate(QemuDiskImageBase):
format: Optional[QemuDiskImageFormat] = Field(None, description="Image format type")
size: Optional[int] = Field(None, description="Image size in Megabytes")
extend: Optional[int] = Field(None, description="Number of Megabytes to extend the image")
-1
View File
@@ -19,7 +19,6 @@ from typing import Optional
class Version(BaseModel):
controller_host: Optional[str] = Field(None, description="Controller hostname or IP address")
version: str = Field(..., description="Version number")
local: Optional[bool] = Field(None, description="Whether this is a local server or not")