mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-06 07:11:13 +02:00
fix: address appliance v8 install review findings
- install: resolve the image directory from the version's settings type and skip image handling for docker appliances; guard appliance.images - appliance schema: validate template_properties against template_type, align cpu_throttling with the qemu template, add kvm and version idlepc - conversion: map IOU image to path, kvm disable to accel=tcg, inherit only same-type default settings, symbol fallback from the effective category, template_properties cannot override structural fields - allow clearing netmiko_device_type with an empty string - download the template symbol regardless of the level it is defined at and give qemu guests a default symbol
This commit is contained in:
10 files changed
+603
-39
No files matched your search
@@ -19,7 +19,7 @@
|
||||
from enum import Enum
|
||||
from typing import Annotated, List, Literal, Optional, Union
|
||||
from uuid import UUID
|
||||
from pydantic import AnyUrl, BaseModel, Discriminator, EmailStr, Field, Tag
|
||||
from pydantic import AnyUrl, BaseModel, Discriminator, EmailStr, Field, Tag, model_validator
|
||||
from ..common import ExtraConfig
|
||||
|
||||
|
||||
@@ -567,14 +567,23 @@ class QemuPropertiesV8(BaseModel):
|
||||
title='Optional define the disk boot priory. Refer to -boot option in qemu manual for more details.',
|
||||
)
|
||||
kernel_command_line: Optional[str] = Field(None, title='Command line parameters send to the kernel')
|
||||
kvm: Optional[Kvm] = Field(None, title='KVM requirements')
|
||||
options: Optional[str] = Field(None, title='Optional additional qemu command line options')
|
||||
cpu_throttling: Optional[Annotated[float, Field(ge=0.0, le=100.0)]] = Field(None, title='Throttle the CPU')
|
||||
cpu_throttling: Optional[Annotated[int, Field(ge=0, le=800)]] = Field(None, title='Throttle the CPU')
|
||||
tpm: Optional[bool] = Field(None, title='Enable the Trusted Platform Module (TPM)')
|
||||
uefi: Optional[bool] = Field(None, title='Enable the UEFI boot mode')
|
||||
on_close: Optional[QemuOnClose] = Field(None, title='Action to execute on the VM is closed')
|
||||
process_priority: Optional[QemuProcessPriority] = Field(None, title='Process priority for QEMU')
|
||||
|
||||
|
||||
_V8_PROPERTIES_MODELS = {
|
||||
TemplateType.qemu: QemuPropertiesV8,
|
||||
TemplateType.dynamips: DynamipsPropertiesV8,
|
||||
TemplateType.iou: IouPropertiesV8,
|
||||
TemplateType.docker: DockerPropertiesV8,
|
||||
}
|
||||
|
||||
|
||||
class TemplateSetting(BaseModel):
|
||||
"""Emulator settings configuration (v8)"""
|
||||
|
||||
@@ -587,12 +596,34 @@ class TemplateSetting(BaseModel):
|
||||
title='Properties for the template'
|
||||
)
|
||||
|
||||
@model_validator(mode='before')
|
||||
@classmethod
|
||||
def _validate_template_properties(cls, data):
|
||||
"""
|
||||
Validate template_properties against the model matching template_type.
|
||||
The template_type discriminator lives at the settings level (not inside
|
||||
template_properties), so the union cannot be discriminated by pydantic
|
||||
alone and would misroute properties between the per-type models.
|
||||
"""
|
||||
|
||||
if isinstance(data, dict):
|
||||
# work on a copy: replacing template_properties with the validated
|
||||
# model must not mutate the caller's data
|
||||
data = data.copy()
|
||||
template_type = data.get("template_type")
|
||||
template_properties = data.get("template_properties")
|
||||
model = _V8_PROPERTIES_MODELS.get(template_type)
|
||||
if model is not None and isinstance(template_properties, dict):
|
||||
data["template_properties"] = model.model_validate(template_properties)
|
||||
return data
|
||||
|
||||
|
||||
class ApplianceVersionV8(BaseModel):
|
||||
"""Appliance version definition (v8)"""
|
||||
|
||||
name: str = Field(..., title='Name of the version')
|
||||
settings: Optional[str] = Field(None, title='Template settings to use to run the version')
|
||||
idlepc: Optional[str] = Field(None, pattern=r'^0x[0-9a-f]{8}')
|
||||
category: Optional[Category] = Field(None, title='Category of the version')
|
||||
installation_instructions: Optional[str] = Field(None, title='Optional installation instructions for the version')
|
||||
usage: Optional[str] = Field(None, title='Optional instructions about using the version')
|
||||
@@ -633,7 +664,7 @@ class ApplianceV1_6(BaseModel):
|
||||
usage: Optional[str] = Field(None, title='How to use the appliance')
|
||||
symbol: Optional[str] = Field(None, title='An optional symbol for the appliance')
|
||||
netmiko_device_type: Optional[str] = Field(
|
||||
None, title='Device type for Netmiko-based automation tools', pattern=r'^[a-z0-9_]+$'
|
||||
None, title='Device type for Netmiko-based automation tools', pattern=r'^[a-z0-9_]+$|^$'
|
||||
)
|
||||
first_port_name: Optional[str] = Field(None, title='Optional name of the first networking port example: eth0')
|
||||
port_name_format: Optional[str] = Field(None, title='Optional formating of the networking port example: eth{0}')
|
||||
@@ -689,7 +720,7 @@ class ApplianceV8(BaseModel):
|
||||
default_password: Optional[str] = Field(None, title='Default password for the appliance')
|
||||
symbol: Optional[str] = Field(None, title='An optional symbol for the appliance')
|
||||
netmiko_device_type: Optional[str] = Field(
|
||||
None, title='Device type for Netmiko-based automation tools', pattern=r'^[a-z0-9_]+$'
|
||||
None, title='Device type for Netmiko-based automation tools', pattern=r'^[a-z0-9_]+$|^$'
|
||||
)
|
||||
tags: Optional[List[str]] = Field(None, title='User-defined metadata tags for the appliance')
|
||||
settings: List[TemplateSetting] = Field(..., title='Settings for running the appliance')
|
||||
|
||||
@@ -119,7 +119,7 @@ class NodeBase(BaseModel):
|
||||
netmiko_device_type: Optional[str] = Field(
|
||||
None,
|
||||
description="Device type for Netmiko-based automation tools, overrides the template value",
|
||||
pattern=r"^[a-z0-9_]+$",
|
||||
pattern=r"^[a-z0-9_]+$|^$",
|
||||
)
|
||||
aux: Optional[int] = Field(None, gt=0, le=65535, description="Auxiliary console TCP port")
|
||||
aux_type: Optional[ConsoleType] = None
|
||||
|
||||
@@ -51,7 +51,7 @@ class TemplateBase(BaseModel):
|
||||
netmiko_device_type: Optional[str] = Field(
|
||||
None,
|
||||
description="Device type for Netmiko-based automation tools (e.g. 'cisco_xr' or 'nokia_srl')",
|
||||
pattern=r"^[a-z0-9_]+$",
|
||||
pattern=r"^[a-z0-9_]+$|^$",
|
||||
)
|
||||
tags: Optional[List[str]] = Field(
|
||||
default_factory=list,
|
||||
|
||||
Reference in new issue
Block a user