mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-03 05:51:15 +02:00
refactor: ruff autofixes
This commit is contained in:
455 files changed
+12322
-14762
No files matched your search
@@ -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]]
|
||||
|
||||
@@ -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
|
||||
@@ -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")
|
||||
@@ -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]]
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
|
||||
@@ -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)")
|
||||
@@ -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)")
|
||||
|
||||
@@ -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
@@ -20,6 +20,5 @@ from pydantic import BaseModel
|
||||
|
||||
|
||||
class DateTimeModelMixin(BaseModel):
|
||||
|
||||
created_at: Optional[datetime] = None
|
||||
updated_at: Optional[datetime] = None
|
||||
@@ -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")
|
||||
|
||||
@@ -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}}
|
||||
)
|
||||
@@ -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")
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
@@ -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
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
Reference in new issue
Block a user