mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-12-22 06:07:51 +00:00
Merge pull request #2091 from GNS3/use-themed-symbols
Let the controller allocate symbols
This commit is contained in:
commit
bd9af3fe90
@ -49,6 +49,11 @@ symbols_path = /home/gns3/GNS3/symbols
|
|||||||
; Path where custom configs are stored
|
; Path where custom configs are stored
|
||||||
configs_path = /home/gns3/GNS3/configs
|
configs_path = /home/gns3/GNS3/configs
|
||||||
|
|
||||||
|
; Default symbol theme
|
||||||
|
; Currently available themes are "Classic", Affinity-square-blue", "Affinity-square-red"
|
||||||
|
; "Affinity-square-gray", "Affinity-circle-blue", "Affinity-circle-red" and "Affinity-circle-gray"
|
||||||
|
default_symbol_theme = Affinity-square-blue
|
||||||
|
|
||||||
; Option to automatically send crash reports to the GNS3 team
|
; Option to automatically send crash reports to the GNS3 team
|
||||||
report_errors = True
|
report_errors = True
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ router = APIRouter()
|
|||||||
@router.get("")
|
@router.get("")
|
||||||
async def get_appliances(
|
async def get_appliances(
|
||||||
update: Optional[bool] = False,
|
update: Optional[bool] = False,
|
||||||
symbol_theme: Optional[str] = "Classic"
|
symbol_theme: Optional[str] = None
|
||||||
) -> List[schemas.Appliance]:
|
) -> List[schemas.Appliance]:
|
||||||
"""
|
"""
|
||||||
Return all appliances known by the controller.
|
Return all appliances known by the controller.
|
||||||
@ -56,7 +56,7 @@ async def get_appliances(
|
|||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
if update:
|
if update:
|
||||||
await controller.appliance_manager.download_appliances()
|
await controller.appliance_manager.download_appliances()
|
||||||
controller.appliance_manager.load_appliances(symbol_theme=symbol_theme)
|
controller.appliance_manager.load_appliances(symbol_theme)
|
||||||
return [c.asdict() for c in controller.appliance_manager.appliances.values()]
|
return [c.asdict() for c in controller.appliance_manager.appliances.values()]
|
||||||
|
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ class ApplianceManager:
|
|||||||
template_data = await self._appliance_to_template(appliance)
|
template_data = await self._appliance_to_template(appliance)
|
||||||
await self._create_template(template_data, templates_repo, rbac_repo, current_user)
|
await self._create_template(template_data, templates_repo, rbac_repo, current_user)
|
||||||
|
|
||||||
def load_appliances(self, symbol_theme: str = "Classic") -> None:
|
def load_appliances(self, symbol_theme: str = None) -> None:
|
||||||
"""
|
"""
|
||||||
Loads appliance files from disk.
|
Loads appliance files from disk.
|
||||||
"""
|
"""
|
||||||
@ -326,6 +326,8 @@ class ApplianceManager:
|
|||||||
from . import Controller
|
from . import Controller
|
||||||
|
|
||||||
controller = Controller.instance()
|
controller = Controller.instance()
|
||||||
|
if not symbol_theme:
|
||||||
|
symbol_theme = controller.symbols.theme
|
||||||
category = appliance["category"]
|
category = appliance["category"]
|
||||||
if category == "guest":
|
if category == "guest":
|
||||||
if "docker" in appliance:
|
if "docker" in appliance:
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
CLASSIC_SYMBOL_THEME = {
|
CLASSIC_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/classic/cloud.svg",
|
"cloud": ":/symbols/classic/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/classic/ethernet_switch.svg",
|
"ethernet_switch": ":/symbols/classic/ethernet_switch.svg",
|
||||||
"ethernet_hub": ":/symbols/classic/hub.svg",
|
"hub": ":/symbols/classic/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/classic/frame_relay_switch.svg",
|
"frame_relay_switch": ":/symbols/classic/frame_relay_switch.svg",
|
||||||
"atm_switch": ":/symbols/classic/atm_switch.svg",
|
"atm_switch": ":/symbols/classic/atm_switch.svg",
|
||||||
"router": ":/symbols/classic/router.svg",
|
"router": ":/symbols/classic/router.svg",
|
||||||
@ -36,8 +36,8 @@ CLASSIC_SYMBOL_THEME = {
|
|||||||
AFFINITY_SQUARE_BLUE_SYMBOL_THEME = {
|
AFFINITY_SQUARE_BLUE_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/square/blue/cloud.svg",
|
"cloud": ":/symbols/affinity/square/blue/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/square/blue/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/square/blue/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/square/blue/hub.svg",
|
"hub": ":/symbols/affinity/square/blue/hub.svg",
|
||||||
"frame_relay_switch.svg": ":/symbols/affinity/square/blue/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/square/blue/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/square/blue/atm.svg",
|
"atm_switch": ":/symbols/affinity/square/blue/atm.svg",
|
||||||
"router": ":/symbols/affinity/square/blue/router.svg",
|
"router": ":/symbols/affinity/square/blue/router.svg",
|
||||||
"multilayer_switch": ":/symbols/affinity/square/blue/switch_multilayer.svg",
|
"multilayer_switch": ":/symbols/affinity/square/blue/switch_multilayer.svg",
|
||||||
@ -53,7 +53,7 @@ AFFINITY_SQUARE_BLUE_SYMBOL_THEME = {
|
|||||||
AFFINITY_SQUARE_RED_SYMBOL_THEME = {
|
AFFINITY_SQUARE_RED_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/square/red/cloud.svg",
|
"cloud": ":/symbols/affinity/square/red/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/square/red/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/square/red/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/square/red/hub.svg",
|
"hub": ":/symbols/affinity/square/red/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/affinity/square/red/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/square/red/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/square/red/atm.svg",
|
"atm_switch": ":/symbols/affinity/square/red/atm.svg",
|
||||||
"router": ":/symbols/affinity/square/red/router.svg",
|
"router": ":/symbols/affinity/square/red/router.svg",
|
||||||
@ -70,7 +70,7 @@ AFFINITY_SQUARE_RED_SYMBOL_THEME = {
|
|||||||
AFFINITY_SQUARE_GRAY_SYMBOL_THEME = {
|
AFFINITY_SQUARE_GRAY_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/square/gray/cloud.svg",
|
"cloud": ":/symbols/affinity/square/gray/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/square/gray/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/square/gray/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/square/gray/hub.svg",
|
"hub": ":/symbols/affinity/square/gray/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/affinity/square/gray/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/square/gray/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/square/gray/atm.svg",
|
"atm_switch": ":/symbols/affinity/square/gray/atm.svg",
|
||||||
"router": ":/symbols/affinity/square/gray/router.svg",
|
"router": ":/symbols/affinity/square/gray/router.svg",
|
||||||
@ -87,7 +87,7 @@ AFFINITY_SQUARE_GRAY_SYMBOL_THEME = {
|
|||||||
AFFINITY_CIRCLE_BLUE_SYMBOL_THEME = {
|
AFFINITY_CIRCLE_BLUE_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/circle/blue/cloud.svg",
|
"cloud": ":/symbols/affinity/circle/blue/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/circle/blue/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/circle/blue/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/circle/blue/hub.svg",
|
"hub": ":/symbols/affinity/circle/blue/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/affinity/circle/blue/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/circle/blue/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/circle/blue/atm.svg",
|
"atm_switch": ":/symbols/affinity/circle/blue/atm.svg",
|
||||||
"router": ":/symbols/affinity/circle/blue/router.svg",
|
"router": ":/symbols/affinity/circle/blue/router.svg",
|
||||||
@ -104,7 +104,7 @@ AFFINITY_CIRCLE_BLUE_SYMBOL_THEME = {
|
|||||||
AFFINITY_CIRCLE_RED_SYMBOL_THEME = {
|
AFFINITY_CIRCLE_RED_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/circle/red/cloud.svg",
|
"cloud": ":/symbols/affinity/circle/red/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/circle/red/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/circle/red/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/circle/red/hub.svg",
|
"hub": ":/symbols/affinity/circle/red/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/affinity/circle/red/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/circle/red/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/circle/red/atm.svg",
|
"atm_switch": ":/symbols/affinity/circle/red/atm.svg",
|
||||||
"router": ":/symbols/affinity/circle/red/router.svg",
|
"router": ":/symbols/affinity/circle/red/router.svg",
|
||||||
@ -121,7 +121,7 @@ AFFINITY_CIRCLE_RED_SYMBOL_THEME = {
|
|||||||
AFFINITY_CIRCLE_GRAY_SYMBOL_THEME = {
|
AFFINITY_CIRCLE_GRAY_SYMBOL_THEME = {
|
||||||
"cloud": ":/symbols/affinity/circle/gray/cloud.svg",
|
"cloud": ":/symbols/affinity/circle/gray/cloud.svg",
|
||||||
"ethernet_switch": ":/symbols/affinity/circle/gray/switch.svg",
|
"ethernet_switch": ":/symbols/affinity/circle/gray/switch.svg",
|
||||||
"ethernet_hub": ":/symbols/affinity/circle/gray/hub.svg",
|
"hub": ":/symbols/affinity/circle/gray/hub.svg",
|
||||||
"frame_relay_switch": ":/symbols/affinity/circle/gray/isdn.svg",
|
"frame_relay_switch": ":/symbols/affinity/circle/gray/isdn.svg",
|
||||||
"atm_switch": ":/symbols/affinity/circle/gray/atm.svg",
|
"atm_switch": ":/symbols/affinity/circle/gray/atm.svg",
|
||||||
"router": ":/symbols/affinity/circle/gray/router.svg",
|
"router": ":/symbols/affinity/circle/gray/router.svg",
|
||||||
|
@ -43,7 +43,9 @@ class Symbols:
|
|||||||
|
|
||||||
# Keep a cache of symbols size
|
# Keep a cache of symbols size
|
||||||
self._symbol_size_cache = {}
|
self._symbol_size_cache = {}
|
||||||
self._current_theme = "Classic"
|
|
||||||
|
self._server_config = Config.instance().settings.Server
|
||||||
|
self._current_theme = self._server_config.default_symbol_theme
|
||||||
self._themes = BUILTIN_SYMBOL_THEMES
|
self._themes = BUILTIN_SYMBOL_THEMES
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -66,10 +68,11 @@ class Symbols:
|
|||||||
|
|
||||||
theme = self._themes.get(symbol_theme, None)
|
theme = self._themes.get(symbol_theme, None)
|
||||||
if not theme:
|
if not theme:
|
||||||
raise ControllerNotFoundError(f"Could not find symbol theme '{symbol_theme}'")
|
log.warning(f"Could not find symbol theme '{symbol_theme}'")
|
||||||
|
return None
|
||||||
symbol_path = theme.get(symbol)
|
symbol_path = theme.get(symbol)
|
||||||
if symbol_path not in self._symbols_path:
|
if symbol_path not in self._symbols_path:
|
||||||
log.warning(f"Default symbol {symbol_path} was not found")
|
log.warning(f"Default symbol {symbol} was not found")
|
||||||
return None
|
return None
|
||||||
return symbol_path
|
return symbol_path
|
||||||
|
|
||||||
@ -125,7 +128,17 @@ class Symbols:
|
|||||||
|
|
||||||
return self._symbols_path.get(symbol_id)
|
return self._symbols_path.get(symbol_id)
|
||||||
|
|
||||||
|
def resolve_symbol(self, symbol_name):
|
||||||
|
|
||||||
|
if not symbol_name.startswith(":/"):
|
||||||
|
symbol = self.get_default_symbol(symbol_name, self._current_theme)
|
||||||
|
if symbol:
|
||||||
|
return symbol
|
||||||
|
return symbol_name
|
||||||
|
|
||||||
def get_path(self, symbol_id):
|
def get_path(self, symbol_id):
|
||||||
|
|
||||||
|
symbol_id = self.resolve_symbol(symbol_id)
|
||||||
try:
|
try:
|
||||||
return self._symbols_path[symbol_id]
|
return self._symbols_path[symbol_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
@ -109,6 +109,17 @@ class ServerProtocol(str, Enum):
|
|||||||
https = "https"
|
https = "https"
|
||||||
|
|
||||||
|
|
||||||
|
class BuiltinSymbolTheme(str, Enum):
|
||||||
|
|
||||||
|
classic = "Classic"
|
||||||
|
affinity_square_blue = "Affinity-square-blue"
|
||||||
|
affinity_square_red = "Affinity-square-red"
|
||||||
|
affinity_square_gray = "Affinity-square-gray"
|
||||||
|
affinity_circle_blue = "Affinity-circle-blue"
|
||||||
|
affinity_circle_red = "Affinity-circle-red"
|
||||||
|
affinity_circle_gray = "Affinity-circle-gray"
|
||||||
|
|
||||||
|
|
||||||
class ServerSettings(BaseModel):
|
class ServerSettings(BaseModel):
|
||||||
|
|
||||||
local: bool = False
|
local: bool = False
|
||||||
@ -124,6 +135,7 @@ class ServerSettings(BaseModel):
|
|||||||
appliances_path: str = "~/GNS3/appliances"
|
appliances_path: str = "~/GNS3/appliances"
|
||||||
symbols_path: str = "~/GNS3/symbols"
|
symbols_path: str = "~/GNS3/symbols"
|
||||||
configs_path: str = "~/GNS3/configs"
|
configs_path: str = "~/GNS3/configs"
|
||||||
|
default_symbol_theme: BuiltinSymbolTheme = BuiltinSymbolTheme.affinity_square_blue
|
||||||
report_errors: bool = True
|
report_errors: bool = True
|
||||||
additional_images_paths: List[str] = Field(default_factory=list)
|
additional_images_paths: List[str] = Field(default_factory=list)
|
||||||
console_start_port_range: int = Field(5000, gt=0, le=65535)
|
console_start_port_range: int = Field(5000, gt=0, le=65535)
|
||||||
|
@ -31,7 +31,7 @@ class CloudTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "Cloud{0}"
|
default_name_format: Optional[str] = "Cloud{0}"
|
||||||
symbol: Optional[str] = ":/symbols/cloud.svg"
|
symbol: Optional[str] = "cloud"
|
||||||
ports_mapping: List[Union[EthernetPort, TAPPort, UDPPort]] = Field(default_factory=list)
|
ports_mapping: List[Union[EthernetPort, TAPPort, UDPPort]] = Field(default_factory=list)
|
||||||
remote_console_host: Optional[str] = Field("127.0.0.1", description="Remote console host or IP")
|
remote_console_host: Optional[str] = Field("127.0.0.1", description="Remote console host or IP")
|
||||||
remote_console_port: Optional[int] = Field(23, gt=0, le=65535, description="Remote console TCP port")
|
remote_console_port: Optional[int] = Field(23, gt=0, le=65535, description="Remote console TCP port")
|
||||||
|
@ -26,7 +26,7 @@ class DockerTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "{name}-{0}"
|
default_name_format: Optional[str] = "{name}-{0}"
|
||||||
symbol: Optional[str] = ":/symbols/docker_guest.svg"
|
symbol: Optional[str] = "docker_guest"
|
||||||
image: str = Field(..., description="Docker image name")
|
image: str = Field(..., description="Docker image name")
|
||||||
adapters: Optional[int] = Field(1, ge=0, le=100, description="Number of adapters")
|
adapters: Optional[int] = Field(1, ge=0, le=100, description="Number of adapters")
|
||||||
start_command: Optional[str] = Field("", description="Docker CMD entry")
|
start_command: Optional[str] = Field("", description="Docker CMD entry")
|
||||||
|
@ -34,7 +34,7 @@ class DynamipsTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "router"
|
category: Optional[Category] = "router"
|
||||||
default_name_format: Optional[str] = "R{0}"
|
default_name_format: Optional[str] = "R{0}"
|
||||||
symbol: Optional[str] = ":/symbols/router.svg"
|
symbol: Optional[str] = "router"
|
||||||
platform: DynamipsPlatform = Field(..., description="Cisco router platform")
|
platform: DynamipsPlatform = Field(..., description="Cisco router platform")
|
||||||
image: str = Field(..., description="Path to the IOS image")
|
image: str = Field(..., description="Path to the IOS image")
|
||||||
exec_area: Optional[int] = Field(64, description="Exec area value")
|
exec_area: Optional[int] = Field(64, description="Exec area value")
|
||||||
|
@ -37,7 +37,7 @@ class EthernetHubTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "switch"
|
category: Optional[Category] = "switch"
|
||||||
default_name_format: Optional[str] = "Hub{0}"
|
default_name_format: Optional[str] = "Hub{0}"
|
||||||
symbol: Optional[str] = ":/symbols/hub.svg"
|
symbol: Optional[str] = "hub"
|
||||||
ports_mapping: Optional[List[EthernetHubPort]] = Field(DEFAULT_PORTS, description="Ports")
|
ports_mapping: Optional[List[EthernetHubPort]] = Field(DEFAULT_PORTS, description="Ports")
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class EthernetSwitchTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "switch"
|
category: Optional[Category] = "switch"
|
||||||
default_name_format: Optional[str] = "Switch{0}"
|
default_name_format: Optional[str] = "Switch{0}"
|
||||||
symbol: Optional[str] = ":/symbols/ethernet_switch.svg"
|
symbol: Optional[str] = "ethernet_switch"
|
||||||
ports_mapping: Optional[List[EthernetSwitchPort]] = Field(DEFAULT_PORTS, description="Ports")
|
ports_mapping: Optional[List[EthernetSwitchPort]] = Field(DEFAULT_PORTS, description="Ports")
|
||||||
console_type: Optional[ConsoleType] = Field("none", description="Console type")
|
console_type: Optional[ConsoleType] = Field("none", description="Console type")
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ class IOUTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "router"
|
category: Optional[Category] = "router"
|
||||||
default_name_format: Optional[str] = "IOU{0}"
|
default_name_format: Optional[str] = "IOU{0}"
|
||||||
symbol: Optional[str] = ":/symbols/multilayer_switch.svg"
|
symbol: Optional[str] = "multilayer_switch"
|
||||||
path: str = Field(..., description="Path of IOU executable")
|
path: str = Field(..., description="Path of IOU executable")
|
||||||
ethernet_adapters: Optional[int] = Field(2, description="Number of ethernet adapters")
|
ethernet_adapters: Optional[int] = Field(2, description="Number of ethernet adapters")
|
||||||
serial_adapters: Optional[int] = Field(2, description="Number of serial adapters")
|
serial_adapters: Optional[int] = Field(2, description="Number of serial adapters")
|
||||||
|
@ -35,7 +35,7 @@ class QemuTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "{name}-{0}"
|
default_name_format: Optional[str] = "{name}-{0}"
|
||||||
symbol: Optional[str] = ":/symbols/qemu_guest.svg"
|
symbol: Optional[str] = "qemu_guest"
|
||||||
qemu_path: Optional[str] = Field("", description="Qemu executable path")
|
qemu_path: Optional[str] = Field("", description="Qemu executable path")
|
||||||
platform: Optional[QemuPlatform] = Field("x86_64", description="Platform to emulate")
|
platform: Optional[QemuPlatform] = Field("x86_64", description="Platform to emulate")
|
||||||
linked_clone: Optional[bool] = Field(True, description="Whether the VM is a linked clone or not")
|
linked_clone: Optional[bool] = Field(True, description="Whether the VM is a linked clone or not")
|
||||||
|
@ -30,7 +30,7 @@ class VirtualBoxTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "{name}-{0}"
|
default_name_format: Optional[str] = "{name}-{0}"
|
||||||
symbol: Optional[str] = ":/symbols/vbox_guest.svg"
|
symbol: Optional[str] = "vbox_guest"
|
||||||
vmname: str = Field(..., description="VirtualBox VM name (in VirtualBox itself)")
|
vmname: str = Field(..., description="VirtualBox VM name (in VirtualBox itself)")
|
||||||
ram: Optional[int] = Field(256, gt=0, description="Amount of RAM in MB")
|
ram: Optional[int] = Field(256, gt=0, description="Amount of RAM in MB")
|
||||||
linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not")
|
linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not")
|
||||||
|
@ -31,7 +31,7 @@ class VMwareTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "{name}-{0}"
|
default_name_format: Optional[str] = "{name}-{0}"
|
||||||
symbol: Optional[str] = ":/symbols/vmware_guest.svg"
|
symbol: Optional[str] = "vmware_guest"
|
||||||
vmx_path: str = Field(..., description="Path to the vmx file")
|
vmx_path: str = Field(..., description="Path to the vmx file")
|
||||||
linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not")
|
linked_clone: Optional[bool] = Field(False, description="Whether the VM is a linked clone or not")
|
||||||
first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0")
|
first_port_name: Optional[str] = Field("", description="Optional name of the first networking port example: eth0")
|
||||||
|
@ -26,7 +26,7 @@ class VPCSTemplate(TemplateBase):
|
|||||||
|
|
||||||
category: Optional[Category] = "guest"
|
category: Optional[Category] = "guest"
|
||||||
default_name_format: Optional[str] = "PC{0}"
|
default_name_format: Optional[str] = "PC{0}"
|
||||||
symbol: Optional[str] = ":/symbols/vpcs_guest.svg"
|
symbol: Optional[str] = "vpcs_guest"
|
||||||
base_script_file: Optional[str] = Field("vpcs_base_config.txt", description="Script file")
|
base_script_file: Optional[str] = Field("vpcs_base_config.txt", description="Script file")
|
||||||
console_type: Optional[ConsoleType] = Field("telnet", description="Console type")
|
console_type: Optional[ConsoleType] = Field("telnet", description="Console type")
|
||||||
console_auto_start: Optional[bool] = Field(
|
console_auto_start: Optional[bool] = Field(
|
||||||
|
@ -86,7 +86,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "Cloud",
|
"name": "Cloud",
|
||||||
"default_name_format": "Cloud{0}",
|
"default_name_format": "Cloud{0}",
|
||||||
"category": "guest",
|
"category": "guest",
|
||||||
"symbol": ":/symbols/cloud.svg",
|
"symbol": "cloud",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -96,7 +96,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "NAT",
|
"name": "NAT",
|
||||||
"default_name_format": "NAT{0}",
|
"default_name_format": "NAT{0}",
|
||||||
"category": "guest",
|
"category": "guest",
|
||||||
"symbol": ":/symbols/cloud.svg",
|
"symbol": "cloud",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -106,7 +106,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "VPCS",
|
"name": "VPCS",
|
||||||
"default_name_format": "PC{0}",
|
"default_name_format": "PC{0}",
|
||||||
"category": "guest",
|
"category": "guest",
|
||||||
"symbol": ":/symbols/vpcs_guest.svg",
|
"symbol": "vpcs_guest",
|
||||||
"base_script_file": "vpcs_base_config.txt",
|
"base_script_file": "vpcs_base_config.txt",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
@ -118,7 +118,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"console_type": "none",
|
"console_type": "none",
|
||||||
"default_name_format": "Switch{0}",
|
"default_name_format": "Switch{0}",
|
||||||
"category": "switch",
|
"category": "switch",
|
||||||
"symbol": ":/symbols/ethernet_switch.svg",
|
"symbol": "ethernet_switch",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -128,7 +128,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "Ethernet hub",
|
"name": "Ethernet hub",
|
||||||
"default_name_format": "Hub{0}",
|
"default_name_format": "Hub{0}",
|
||||||
"category": "switch",
|
"category": "switch",
|
||||||
"symbol": ":/symbols/hub.svg",
|
"symbol": "hub",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -138,7 +138,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "Frame Relay switch",
|
"name": "Frame Relay switch",
|
||||||
"default_name_format": "FRSW{0}",
|
"default_name_format": "FRSW{0}",
|
||||||
"category": "switch",
|
"category": "switch",
|
||||||
"symbol": ":/symbols/frame_relay_switch.svg",
|
"symbol": "frame_relay_switch",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -148,7 +148,7 @@ BUILTIN_TEMPLATES = [
|
|||||||
"name": "ATM switch",
|
"name": "ATM switch",
|
||||||
"default_name_format": "ATMSW{0}",
|
"default_name_format": "ATMSW{0}",
|
||||||
"category": "switch",
|
"category": "switch",
|
||||||
"symbol": ":/symbols/atm_switch.svg",
|
"symbol": "atm_switch",
|
||||||
"compute_id": None,
|
"compute_id": None,
|
||||||
"builtin": True,
|
"builtin": True,
|
||||||
},
|
},
|
||||||
@ -163,6 +163,10 @@ class TemplatesService:
|
|||||||
from gns3server.controller import Controller
|
from gns3server.controller import Controller
|
||||||
self._controller = Controller.instance()
|
self._controller = Controller.instance()
|
||||||
|
|
||||||
|
# resolve built-in template symbols
|
||||||
|
for builtin_template in BUILTIN_TEMPLATES:
|
||||||
|
builtin_template["symbol"] = self._controller.symbols.resolve_symbol(builtin_template["symbol"])
|
||||||
|
|
||||||
def get_builtin_template(self, template_id: UUID) -> dict:
|
def get_builtin_template(self, template_id: UUID) -> dict:
|
||||||
|
|
||||||
for builtin_template in BUILTIN_TEMPLATES:
|
for builtin_template in BUILTIN_TEMPLATES:
|
||||||
@ -241,6 +245,8 @@ class TemplatesService:
|
|||||||
except pydantic.ValidationError as e:
|
except pydantic.ValidationError as e:
|
||||||
raise ControllerBadRequestError(f"JSON schema error received while creating new template: {e}")
|
raise ControllerBadRequestError(f"JSON schema error received while creating new template: {e}")
|
||||||
|
|
||||||
|
# resolve the template symbol
|
||||||
|
template_settings["symbol"] = self._controller.symbols.resolve_symbol(template_settings["symbol"])
|
||||||
images_to_add_to_template = await self._find_images(template_create.template_type, template_settings)
|
images_to_add_to_template = await self._find_images(template_create.template_type, template_settings)
|
||||||
db_template = await self._templates_repo.create_template(template_create.template_type, template_settings)
|
db_template = await self._templates_repo.create_template(template_create.template_type, template_settings)
|
||||||
for image in images_to_add_to_template:
|
for image in images_to_add_to_template:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
import os
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
import uuid
|
import uuid
|
||||||
|
import unittest.mock
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from fastapi import FastAPI, status
|
from fastapi import FastAPI, status
|
||||||
@ -313,7 +314,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 512,
|
"ram": 512,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -358,7 +359,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 256,
|
"ram": 256,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -403,7 +404,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 128,
|
"ram": 128,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -450,7 +451,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 192,
|
"ram": 192,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -507,7 +508,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 192,
|
"ram": 192,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -554,7 +555,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 160,
|
"ram": 160,
|
||||||
"sparsemem": True,
|
"sparsemem": True,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -613,7 +614,7 @@ class TestDynamipsTemplate:
|
|||||||
"ram": 160,
|
"ram": 160,
|
||||||
"sparsemem": False,
|
"sparsemem": False,
|
||||||
"startup_config": "ios_base_startup-config.txt",
|
"startup_config": "ios_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/router.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"system_id": "FTX0945W0MY"}
|
"system_id": "FTX0945W0MY"}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -674,7 +675,7 @@ class TestIOUTemplate:
|
|||||||
"ram": 256,
|
"ram": 256,
|
||||||
"serial_adapters": 2,
|
"serial_adapters": 2,
|
||||||
"startup_config": "iou_l3_base_startup-config.txt",
|
"startup_config": "iou_l3_base_startup-config.txt",
|
||||||
"symbol": ":/symbols/multilayer_switch.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"use_default_iou_values": True,
|
"use_default_iou_values": True,
|
||||||
"l1_keepalives": False}
|
"l1_keepalives": False}
|
||||||
|
|
||||||
@ -711,7 +712,7 @@ class TestDockerTemplate:
|
|||||||
"image": "gns3/endhost:latest",
|
"image": "gns3/endhost:latest",
|
||||||
"name": "Docker template",
|
"name": "Docker template",
|
||||||
"start_command": "",
|
"start_command": "",
|
||||||
"symbol": ":/symbols/docker_guest.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"custom_adapters": []}
|
"custom_adapters": []}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
@ -772,7 +773,7 @@ class TestQemuTemplate:
|
|||||||
"process_priority": "normal",
|
"process_priority": "normal",
|
||||||
"qemu_path": "",
|
"qemu_path": "",
|
||||||
"ram": 512,
|
"ram": 512,
|
||||||
"symbol": ":/symbols/qemu_guest.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"usage": "",
|
"usage": "",
|
||||||
"custom_adapters": []}
|
"custom_adapters": []}
|
||||||
|
|
||||||
@ -810,7 +811,7 @@ class TestVMwareTemplate:
|
|||||||
"on_close": "power_off",
|
"on_close": "power_off",
|
||||||
"port_name_format": "Ethernet{0}",
|
"port_name_format": "Ethernet{0}",
|
||||||
"port_segment_size": 0,
|
"port_segment_size": 0,
|
||||||
"symbol": ":/symbols/vmware_guest.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"use_any_adapter": False,
|
"use_any_adapter": False,
|
||||||
"vmx_path": vmx_path,
|
"vmx_path": vmx_path,
|
||||||
"custom_adapters": []}
|
"custom_adapters": []}
|
||||||
@ -849,7 +850,7 @@ class TestVirtualBoxTemplate:
|
|||||||
"port_name_format": "Ethernet{0}",
|
"port_name_format": "Ethernet{0}",
|
||||||
"port_segment_size": 0,
|
"port_segment_size": 0,
|
||||||
"ram": 256,
|
"ram": 256,
|
||||||
"symbol": ":/symbols/vbox_guest.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"use_any_adapter": False,
|
"use_any_adapter": False,
|
||||||
"vmname": "My VirtualBox VM",
|
"vmname": "My VirtualBox VM",
|
||||||
"custom_adapters": []}
|
"custom_adapters": []}
|
||||||
@ -879,7 +880,7 @@ class TestVPCSTemplate:
|
|||||||
"console_type": "telnet",
|
"console_type": "telnet",
|
||||||
"default_name_format": "PC{0}",
|
"default_name_format": "PC{0}",
|
||||||
"name": "VPCS template",
|
"name": "VPCS template",
|
||||||
"symbol": ":/symbols/vpcs_guest.svg"}
|
"symbol": unittest.mock.ANY}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
assert response.json().get(item) == value
|
assert response.json().get(item) == value
|
||||||
@ -952,7 +953,7 @@ class TestEthernetSwitchTemplate:
|
|||||||
"type": "access",
|
"type": "access",
|
||||||
"vlan": 1
|
"vlan": 1
|
||||||
}],
|
}],
|
||||||
"symbol": ":/symbols/ethernet_switch.svg"}
|
"symbol": unittest.mock.ANY}
|
||||||
|
|
||||||
for item, value in expected_response.items():
|
for item, value in expected_response.items():
|
||||||
assert response.json().get(item) == value
|
assert response.json().get(item) == value
|
||||||
@ -995,7 +996,7 @@ class TestHubTemplate:
|
|||||||
}],
|
}],
|
||||||
"compute_id": "local",
|
"compute_id": "local",
|
||||||
"name": "Ethernet hub template",
|
"name": "Ethernet hub template",
|
||||||
"symbol": ":/symbols/hub.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"default_name_format": "Hub{0}",
|
"default_name_format": "Hub{0}",
|
||||||
"template_type": "ethernet_hub",
|
"template_type": "ethernet_hub",
|
||||||
"category": "switch",
|
"category": "switch",
|
||||||
@ -1024,7 +1025,7 @@ class TestCloudTemplate:
|
|||||||
"default_name_format": "Cloud{0}",
|
"default_name_format": "Cloud{0}",
|
||||||
"name": "Cloud template",
|
"name": "Cloud template",
|
||||||
"ports_mapping": [],
|
"ports_mapping": [],
|
||||||
"symbol": ":/symbols/cloud.svg",
|
"symbol": unittest.mock.ANY,
|
||||||
"remote_console_host": "127.0.0.1",
|
"remote_console_host": "127.0.0.1",
|
||||||
"remote_console_port": 23,
|
"remote_console_port": 23,
|
||||||
"remote_console_type": "none",
|
"remote_console_type": "none",
|
||||||
|
@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
from gns3server.controller.symbols import Symbols
|
from gns3server.controller.symbols import Symbols
|
||||||
|
from gns3server.controller.symbol_themes import BUILTIN_SYMBOL_THEMES
|
||||||
from gns3server.utils.get_resource import get_resource
|
from gns3server.utils.get_resource import get_resource
|
||||||
|
|
||||||
|
|
||||||
@ -49,6 +49,15 @@ def test_get_path():
|
|||||||
assert symbols.get_path(':/symbols/classic/firewall.svg') == get_resource("symbols/classic/firewall.svg")
|
assert symbols.get_path(':/symbols/classic/firewall.svg') == get_resource("symbols/classic/firewall.svg")
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_path_with_themed_symbols():
|
||||||
|
|
||||||
|
symbols = Symbols()
|
||||||
|
for symbol_theme, symbols_table in BUILTIN_SYMBOL_THEMES.items():
|
||||||
|
symbols.theme = symbol_theme
|
||||||
|
for symbol_name, symbol_path in symbols_table.items():
|
||||||
|
assert symbols.get_path(symbol_name) == get_resource(symbol_path[2:])
|
||||||
|
|
||||||
|
|
||||||
def test_get_size():
|
def test_get_size():
|
||||||
|
|
||||||
symbols = Symbols()
|
symbols = Symbols()
|
||||||
|
Loading…
Reference in New Issue
Block a user