feat: add response models for endpoints returning untyped objects

This commit is contained in:
Mark Paronyan committed 2026-10-07 16:49:31 +03:00
1 parent 0836e01525
commit db031416a1
24 files changed
+1192 -53

No files matched your search

@@ -161,3 +161,11 @@ class AutoIdlePC(BaseModel):
model_config = ConfigDict(
json_schema_extra={"example": {"platform": "c7200", "image": "/path/to/c7200_image.bin", "ram": 256}}
)
class IdlePC(BaseModel):
"""
Result of an Idle-PC computation.
"""
idlepc: Optional[str] = Field(None, description="Idle-PC value, null when none was found")
+21
View File
@@ -55,3 +55,24 @@ class GNS3VM(BaseModel):
vcpus: Optional[int] = Field(None, description="Number of CPUs to allocate for the GNS3 VM")
ram: Optional[int] = Field(None, description="Amount of memory to allocate for the GNS3 VM")
port: Optional[int] = Field(None, gt=0, le=65535)
class GNS3VMEngineInfo(BaseModel):
"""
A virtualization engine supported by the GNS3 VM.
"""
engine_id: str = Field(..., description="Engine identifier")
name: str = Field(..., description="Engine display name")
description: str = Field(..., description="Engine description (may contain HTML)")
support_when_exit: bool = Field(..., description="The engine supports the 'when exit' action")
support_headless: bool = Field(..., description="The engine supports headless mode")
support_ram: bool = Field(..., description="The engine supports RAM and vCPUs allocation")
class GNS3VMInfo(BaseModel):
"""
A virtual machine available on a virtualization engine.
"""
vmname: str = Field(..., description="Virtual machine name")
+31 -1
View File
@@ -16,7 +16,8 @@
from datetime import datetime
from enum import Enum
from typing import Annotated, Literal, Optional
from typing import Annotated, List, Literal, Optional
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
@@ -100,3 +101,32 @@ class ImageCompatibility(BaseModel):
class ImageCompatibilityCatalog(BaseModel):
image_sizes: list[int]
has_unknown_sizes: bool
class ImageInstallCreated(BaseModel):
"""
A template created from an image by the automatic installation.
"""
template_id: UUID
name: Optional[str] = None
version: Optional[str] = None
template_type: Optional[str] = None
class ImageInstallSkipped(BaseModel):
"""
An image or template that the automatic installation skipped.
"""
name: Optional[str] = None
reason: str
class ImageInstallResult(BaseModel):
"""
Result of the automatic template installation from images.
"""
created: List[ImageInstallCreated]
skipped: List[ImageInstallSkipped]
+78
View File
@@ -274,3 +274,81 @@ class MarkerDefinitionCreate(BaseModel):
@classmethod
def _both_to_none(cls, v):
return None if v == "both" else v
class Marker(BaseModel):
"""
A traffic-insight marker attached to a link.
"""
bpf: str = Field(..., description="libpcap BPF expression")
tag: Optional[int] = Field(None, description="Correlation id shared by markers replayed together")
enabled: bool = Field(True, description="Whether the marker is capturing")
color: Optional[str] = Field(None, description="Hex color used by the Web UI")
highlight_duration: Optional[int] = Field(None, description="Web UI highlight duration in milliseconds")
capture_node_id: Optional[str] = Field(None, description="Node whose uBridge hosts the marker")
direction: Optional[str] = Field(None, description="'tx' or 'rx', null for both directions")
data_link_type: Optional[str] = Field(None, description="pcap link-layer type of the capture file")
inherited_from: Optional[str] = Field(None, description="Project marker definition this marker was copied from")
class ProjectMarker(Marker):
"""
A marker in the project-wide aggregation, with the link and node it belongs to.
"""
link_id: str
node_id: Optional[str] = None
class MarkerDefinition(BaseModel):
"""
A project-level marker definition inherited by every link.
"""
bpf: str = Field(..., description="libpcap BPF expression")
tag: Optional[int] = Field(None, description="Correlation id shared by markers replayed together")
direction: Optional[str] = Field(None, description="'tx' or 'rx', null for both directions")
color: Optional[str] = Field(None, description="Hex color used by the Web UI")
highlight_duration: Optional[int] = Field(None, description="Web UI highlight duration in milliseconds")
data_link_type: Optional[str] = Field(None, description="pcap link-layer type of inherited markers")
paused: bool = Field(False, description="Whether the inherited markers are paused")
class MarkerDefinitionWithLinks(MarkerDefinition):
"""
A project-level marker definition with the links currently carrying a copy of it.
"""
link_ids: List[str] = Field(..., description="Links carrying an inherited copy of the definition")
class LinkWiresharkRestart(BaseModel):
"""
Result of restarting the Wireshark window of a link capture.
"""
status: str
class LinkFilterParameter(BaseModel):
"""
A parameter of a packet filter.
"""
name: str
type: str
minimum: Optional[int] = None
maximum: Optional[int] = None
unit: Optional[str] = None
class LinkFilterInfo(BaseModel):
"""
A packet filter that can be applied to a link.
"""
type: str = Field(..., description="Filter identifier used as key in the link 'filters' property")
name: str
description: str
parameters: List[LinkFilterParameter]
@@ -0,0 +1,114 @@
#
# Copyright (C) 2026 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import List, Optional
from pydantic import BaseModel, ConfigDict, Field
class ReplaySource(BaseModel):
"""
A capture source (one marker pcap) of a replay tag.
"""
node_id: str
link_id: str
marker: str
data_link_type: str
count: int = Field(..., description="Total frames in the capture, unaffected by filters")
class ReplayFrame(BaseModel):
"""
One frame of the merged replay timeline.
"""
ts: str = Field(..., description="Timestamp string to send back unchanged")
len: int = Field(..., description="Captured length in bytes")
node_id: str
link_id: str
marker: str
frame_number: int = Field(..., description="1-based frame number in the source pcap")
src: Optional[str] = None
dst: Optional[str] = None
proto: Optional[str] = None
info: Optional[str] = None
bg: Optional[str] = Field(None, description="Wireshark coloring rule background")
fg: Optional[str] = Field(None, description="Wireshark coloring rule foreground")
class ReplayTimeline(BaseModel):
"""
Replay timeline of a tag.
"""
tag: int
start: Optional[str] = Field(None, description="Timestamp of the first matching frame")
end: Optional[str] = Field(None, description="Timestamp of the last matching frame")
frame_count: int
sources: List[ReplaySource]
frames: List[ReplayFrame]
class ReplayFrames(BaseModel):
"""
Frames of a replay time window.
"""
frames: List[ReplayFrame]
class ReplayFrameSource(BaseModel):
"""
The source pcap and frame a decoded frame comes from.
"""
node_id: str
link_id: str
marker: str
frame_number: int
class ReplayTreeNode(BaseModel):
"""
A node of the decoded protocol tree.
Keys sharkd adds in the future are passed through unchanged.
"""
model_config = ConfigDict(extra="allow")
element: Optional[str] = Field(None, description="Node type")
label: Optional[str] = Field(None, description="Display text")
name: Optional[str] = Field(None, description="Field name, e.g. 'ip.ttl'")
filter_expr: Optional[str] = Field(None, description="Display filter with the value baked in")
pos: Optional[int] = Field(None, description="Byte offset for hex highlighting")
size: Optional[int] = Field(None, description="Byte length for hex highlighting")
expert: Optional[str] = Field(None, description="Expert severity")
generated: Optional[bool] = Field(None, description="Generated by Wireshark")
children: Optional[List["ReplayTreeNode"]] = Field(None, description="Nested fields")
class ReplayFrameDetail(BaseModel):
"""
One decoded frame.
"""
ts: str
source: ReplayFrameSource
field_count: int
hex: str = Field(..., description="Raw frame bytes as hex")
tree: List[ReplayTreeNode]
+12
View File
@@ -126,3 +126,15 @@ class ProjectCompression(str, Enum):
bzip2 = "bzip2"
lzma = "lzma"
zstd = "zstd"
class ProjectStats(BaseModel):
"""
Project object counts.
"""
nodes: int
links: int
drawings: int
snapshots: int
markers: int
+10
View File
@@ -109,3 +109,13 @@ class Role(DateTimeModelMixin, RoleBase):
is_builtin: bool
privileges: List[Privilege]
model_config = ConfigDict(from_attributes=True)
class ACEEndpoint(BaseModel):
"""
An endpoint that can be used in an ACL entry.
"""
endpoint: str = Field(..., description="Endpoint path to use as the ACE path")
name: str = Field(..., description="Human readable name of the endpoint")
endpoint_type: str = Field(..., description="Kind of resource the endpoint refers to")
+131
View File
@@ -0,0 +1,131 @@
#
# Copyright (C) 2026 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import Dict, List, Optional, Union
from pydantic import BaseModel, Field
class ComputeStatistics(BaseModel):
"""
Resource usage reported by a compute.
Fields come from the compute itself, so a compute running another build
may omit some of them.
"""
memory_total: Optional[int] = None
memory_free: Optional[int] = None
memory_used: Optional[int] = None
swap_total: Optional[int] = None
swap_free: Optional[int] = None
swap_used: Optional[int] = None
cpu_usage_percent: Optional[int] = None
cpu_count: Optional[int] = None
cpu_count_physical: Optional[int] = None
cpu_model: Optional[str] = None
memory_usage_percent: Optional[int] = None
swap_usage_percent: Optional[int] = None
disk_usage_percent: Optional[int] = None
disk_total: Optional[int] = None
disk_used: Optional[int] = None
disk_free: Optional[int] = None
load_average: Optional[List[float]] = None
load_average_percent: Optional[List[float]] = None
class ComputeStatisticsEntry(BaseModel):
"""
Statistics of one compute.
"""
compute_id: str
compute_name: str
statistics: ComputeStatistics
class ProjectCountStatistics(BaseModel):
"""
Project counts by status.
"""
total: int
opened: int
closed: int
class NodeStatistics(BaseModel):
"""
Node counts across all projects.
"""
total: int
open_project_nodes: int
closed_project_nodes: int
by_type: Dict[str, int] = Field(..., description="Node count by node type")
by_status: Dict[str, int] = Field(..., description="Node count by status, open projects only")
class LinkStatistics(BaseModel):
"""
Link counts across all projects.
"""
total: int
capturing: int
class WebWiresharkContainer(BaseModel):
"""
A Web Wireshark container.
"""
project_id: str
project_name: str
container_id: str
status: str
running: bool
active_sessions: Optional[int] = None
memory_limit: Optional[str] = None
cpu_limit: Optional[str] = None
pids_limit: Optional[Union[int, str]] = Field(None, description="Process limit, or 'unlimited'")
memory: Optional[str] = Field(None, description="Current memory usage")
cpu: Optional[str] = Field(None, description="Current CPU usage")
pids: Optional[int] = Field(None, description="Current process count")
class WebWiresharkStatistics(BaseModel):
"""
Web Wireshark container statistics across all opened projects.
"""
total_containers: int
running_containers: int
active_sessions: int
containers: List[WebWiresharkContainer]
class ServerStatistics(BaseModel):
"""
Server statistics.
"""
uptime_seconds: int
computes: List[ComputeStatisticsEntry]
projects: ProjectCountStatistics
nodes: NodeStatistics
links: LinkStatistics
webwireshark: WebWiresharkStatistics
+37
View File
@@ -0,0 +1,37 @@
#
# Copyright (C) 2026 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from pydantic import BaseModel
class SymbolInfo(BaseModel):
"""
A symbol available on the controller.
"""
symbol_id: str
filename: str
theme: str
builtin: bool
class SymbolDimensions(BaseModel):
"""
Symbol dimensions in pixels.
"""
width: int
height: int
+28
View File
@@ -15,6 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from typing import Optional
from uuid import UUID
from pydantic import BaseModel
@@ -41,3 +42,30 @@ class ApiKeyCreate(BaseModel):
"""Schema for creating a new API key."""
name: str
class ApiKey(BaseModel):
"""API key metadata. The secret is never returned after creation."""
api_key_id: UUID
name: str
key_prefix: str
created_at: Optional[str] = None
last_used_at: Optional[str] = None
revoked: bool
class ApiKeyCreated(BaseModel):
"""A newly created API key. The full key is returned only once."""
api_key_id: UUID
api_key: str
name: str
key_prefix: str
created_at: Optional[str] = None
class ApiKeyMessage(BaseModel):
"""Confirmation message returned when an API key is revoked or restored."""
message: str