From bfbac2e93a8bb762e2bc95c50c8b8131ae70db1b Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 25 Jul 2022 12:33:40 +0200 Subject: [PATCH 1/3] Use generic symbol names --- gns3server/controller/symbol_themes.py | 16 ++++----- gns3server/controller/symbols.py | 14 ++++++-- .../controller/templates/cloud_templates.py | 2 +- .../controller/templates/docker_templates.py | 2 +- .../templates/dynamips_templates.py | 2 +- .../templates/ethernet_hub_templates.py | 2 +- .../templates/ethernet_switch_templates.py | 2 +- .../controller/templates/iou_templates.py | 2 +- .../controller/templates/qemu_templates.py | 2 +- .../templates/virtualbox_templates.py | 2 +- .../controller/templates/vmware_templates.py | 2 +- .../controller/templates/vpcs_templates.py | 2 +- gns3server/services/templates.py | 20 +++++++---- tests/api/routes/controller/test_templates.py | 33 ++++++++++--------- tests/controller/test_symbols.py | 11 ++++++- 15 files changed, 70 insertions(+), 44 deletions(-) diff --git a/gns3server/controller/symbol_themes.py b/gns3server/controller/symbol_themes.py index 9ea77ecab..39841e490 100644 --- a/gns3server/controller/symbol_themes.py +++ b/gns3server/controller/symbol_themes.py @@ -19,7 +19,7 @@ CLASSIC_SYMBOL_THEME = { "cloud": ":/symbols/classic/cloud.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", "atm_switch": ":/symbols/classic/atm_switch.svg", "router": ":/symbols/classic/router.svg", @@ -36,8 +36,8 @@ AFFINITY_SQUARE_BLUE_SYMBOL_THEME = { "cloud": ":/symbols/affinity/square/blue/cloud.svg", "ethernet_switch": ":/symbols/affinity/square/blue/switch.svg", - "ethernet_hub": ":/symbols/affinity/square/blue/hub.svg", - "frame_relay_switch.svg": ":/symbols/affinity/square/blue/isdn.svg", + "hub": ":/symbols/affinity/square/blue/hub.svg", + "frame_relay_switch": ":/symbols/affinity/square/blue/isdn.svg", "atm_switch": ":/symbols/affinity/square/blue/atm.svg", "router": ":/symbols/affinity/square/blue/router.svg", "multilayer_switch": ":/symbols/affinity/square/blue/switch_multilayer.svg", @@ -53,7 +53,7 @@ AFFINITY_SQUARE_RED_SYMBOL_THEME = { "cloud": ":/symbols/affinity/square/red/cloud.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", "atm_switch": ":/symbols/affinity/square/red/atm.svg", "router": ":/symbols/affinity/square/red/router.svg", @@ -70,7 +70,7 @@ AFFINITY_SQUARE_GRAY_SYMBOL_THEME = { "cloud": ":/symbols/affinity/square/gray/cloud.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", "atm_switch": ":/symbols/affinity/square/gray/atm.svg", "router": ":/symbols/affinity/square/gray/router.svg", @@ -87,7 +87,7 @@ AFFINITY_CIRCLE_BLUE_SYMBOL_THEME = { "cloud": ":/symbols/affinity/circle/blue/cloud.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", "atm_switch": ":/symbols/affinity/circle/blue/atm.svg", "router": ":/symbols/affinity/circle/blue/router.svg", @@ -104,7 +104,7 @@ AFFINITY_CIRCLE_RED_SYMBOL_THEME = { "cloud": ":/symbols/affinity/circle/red/cloud.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", "atm_switch": ":/symbols/affinity/circle/red/atm.svg", "router": ":/symbols/affinity/circle/red/router.svg", @@ -121,7 +121,7 @@ AFFINITY_CIRCLE_GRAY_SYMBOL_THEME = { "cloud": ":/symbols/affinity/circle/gray/cloud.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", "atm_switch": ":/symbols/affinity/circle/gray/atm.svg", "router": ":/symbols/affinity/circle/gray/router.svg", diff --git a/gns3server/controller/symbols.py b/gns3server/controller/symbols.py index e601c59ae..11fbc35c2 100644 --- a/gns3server/controller/symbols.py +++ b/gns3server/controller/symbols.py @@ -43,7 +43,7 @@ def __init__(self): # Keep a cache of symbols size self._symbol_size_cache = {} - self._current_theme = "Classic" + self._current_theme = "Affinity-square-blue" self._themes = BUILTIN_SYMBOL_THEMES @property @@ -69,7 +69,7 @@ def get_default_symbol(self, symbol, symbol_theme): raise ControllerNotFoundError(f"Could not find symbol theme '{symbol_theme}'") symbol_path = theme.get(symbol) 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 symbol_path @@ -125,7 +125,17 @@ def has_symbol(self, 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): + + symbol_id = self.resolve_symbol(symbol_id) try: return self._symbols_path[symbol_id] except KeyError: diff --git a/gns3server/schemas/controller/templates/cloud_templates.py b/gns3server/schemas/controller/templates/cloud_templates.py index 448a521d2..40695cdd8 100644 --- a/gns3server/schemas/controller/templates/cloud_templates.py +++ b/gns3server/schemas/controller/templates/cloud_templates.py @@ -31,7 +31,7 @@ class CloudTemplate(TemplateBase): category: Optional[Category] = "guest" 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) 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") diff --git a/gns3server/schemas/controller/templates/docker_templates.py b/gns3server/schemas/controller/templates/docker_templates.py index 277caf9e9..9d020cf8c 100644 --- a/gns3server/schemas/controller/templates/docker_templates.py +++ b/gns3server/schemas/controller/templates/docker_templates.py @@ -26,7 +26,7 @@ class DockerTemplate(TemplateBase): category: Optional[Category] = "guest" 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") adapters: Optional[int] = Field(1, ge=0, le=100, description="Number of adapters") start_command: Optional[str] = Field("", description="Docker CMD entry") diff --git a/gns3server/schemas/controller/templates/dynamips_templates.py b/gns3server/schemas/controller/templates/dynamips_templates.py index 36b434610..4c590eec9 100644 --- a/gns3server/schemas/controller/templates/dynamips_templates.py +++ b/gns3server/schemas/controller/templates/dynamips_templates.py @@ -34,7 +34,7 @@ class DynamipsTemplate(TemplateBase): category: Optional[Category] = "router" default_name_format: Optional[str] = "R{0}" - symbol: Optional[str] = ":/symbols/router.svg" + symbol: Optional[str] = "router" platform: DynamipsPlatform = Field(..., description="Cisco router platform") image: str = Field(..., description="Path to the IOS image") exec_area: Optional[int] = Field(64, description="Exec area value") diff --git a/gns3server/schemas/controller/templates/ethernet_hub_templates.py b/gns3server/schemas/controller/templates/ethernet_hub_templates.py index b3fd31016..9501f2e2f 100644 --- a/gns3server/schemas/controller/templates/ethernet_hub_templates.py +++ b/gns3server/schemas/controller/templates/ethernet_hub_templates.py @@ -37,7 +37,7 @@ class EthernetHubTemplate(TemplateBase): category: Optional[Category] = "switch" 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") diff --git a/gns3server/schemas/controller/templates/ethernet_switch_templates.py b/gns3server/schemas/controller/templates/ethernet_switch_templates.py index 80869869f..ab1ab52da 100644 --- a/gns3server/schemas/controller/templates/ethernet_switch_templates.py +++ b/gns3server/schemas/controller/templates/ethernet_switch_templates.py @@ -47,7 +47,7 @@ class EthernetSwitchTemplate(TemplateBase): category: Optional[Category] = "switch" 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") console_type: Optional[ConsoleType] = Field("none", description="Console type") diff --git a/gns3server/schemas/controller/templates/iou_templates.py b/gns3server/schemas/controller/templates/iou_templates.py index 6cb75d806..4f2d3f385 100644 --- a/gns3server/schemas/controller/templates/iou_templates.py +++ b/gns3server/schemas/controller/templates/iou_templates.py @@ -26,7 +26,7 @@ class IOUTemplate(TemplateBase): category: Optional[Category] = "router" 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") ethernet_adapters: Optional[int] = Field(2, description="Number of ethernet adapters") serial_adapters: Optional[int] = Field(2, description="Number of serial adapters") diff --git a/gns3server/schemas/controller/templates/qemu_templates.py b/gns3server/schemas/controller/templates/qemu_templates.py index 18f12c24e..2de491e11 100644 --- a/gns3server/schemas/controller/templates/qemu_templates.py +++ b/gns3server/schemas/controller/templates/qemu_templates.py @@ -35,7 +35,7 @@ class QemuTemplate(TemplateBase): category: Optional[Category] = "guest" 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") 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") diff --git a/gns3server/schemas/controller/templates/virtualbox_templates.py b/gns3server/schemas/controller/templates/virtualbox_templates.py index a35846b5d..34fb6a1d0 100644 --- a/gns3server/schemas/controller/templates/virtualbox_templates.py +++ b/gns3server/schemas/controller/templates/virtualbox_templates.py @@ -30,7 +30,7 @@ class VirtualBoxTemplate(TemplateBase): category: Optional[Category] = "guest" 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)") 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") diff --git a/gns3server/schemas/controller/templates/vmware_templates.py b/gns3server/schemas/controller/templates/vmware_templates.py index e3876f774..7109e5d08 100644 --- a/gns3server/schemas/controller/templates/vmware_templates.py +++ b/gns3server/schemas/controller/templates/vmware_templates.py @@ -31,7 +31,7 @@ class VMwareTemplate(TemplateBase): category: Optional[Category] = "guest" 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") 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") diff --git a/gns3server/schemas/controller/templates/vpcs_templates.py b/gns3server/schemas/controller/templates/vpcs_templates.py index 046c9c3c1..5ed288c99 100644 --- a/gns3server/schemas/controller/templates/vpcs_templates.py +++ b/gns3server/schemas/controller/templates/vpcs_templates.py @@ -26,7 +26,7 @@ class VPCSTemplate(TemplateBase): category: Optional[Category] = "guest" 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") console_type: Optional[ConsoleType] = Field("telnet", description="Console type") console_auto_start: Optional[bool] = Field( diff --git a/gns3server/services/templates.py b/gns3server/services/templates.py index c06671706..62e206dab 100644 --- a/gns3server/services/templates.py +++ b/gns3server/services/templates.py @@ -86,7 +86,7 @@ "name": "Cloud", "default_name_format": "Cloud{0}", "category": "guest", - "symbol": ":/symbols/cloud.svg", + "symbol": "cloud", "compute_id": None, "builtin": True, }, @@ -96,7 +96,7 @@ "name": "NAT", "default_name_format": "NAT{0}", "category": "guest", - "symbol": ":/symbols/cloud.svg", + "symbol": "cloud", "compute_id": None, "builtin": True, }, @@ -106,7 +106,7 @@ "name": "VPCS", "default_name_format": "PC{0}", "category": "guest", - "symbol": ":/symbols/vpcs_guest.svg", + "symbol": "vpcs_guest", "base_script_file": "vpcs_base_config.txt", "compute_id": None, "builtin": True, @@ -118,7 +118,7 @@ "console_type": "none", "default_name_format": "Switch{0}", "category": "switch", - "symbol": ":/symbols/ethernet_switch.svg", + "symbol": "ethernet_switch", "compute_id": None, "builtin": True, }, @@ -128,7 +128,7 @@ "name": "Ethernet hub", "default_name_format": "Hub{0}", "category": "switch", - "symbol": ":/symbols/hub.svg", + "symbol": "hub", "compute_id": None, "builtin": True, }, @@ -138,7 +138,7 @@ "name": "Frame Relay switch", "default_name_format": "FRSW{0}", "category": "switch", - "symbol": ":/symbols/frame_relay_switch.svg", + "symbol": "frame_relay_switch", "compute_id": None, "builtin": True, }, @@ -148,7 +148,7 @@ "name": "ATM switch", "default_name_format": "ATMSW{0}", "category": "switch", - "symbol": ":/symbols/atm_switch.svg", + "symbol": "atm_switch", "compute_id": None, "builtin": True, }, @@ -163,6 +163,10 @@ def __init__(self, templates_repo: TemplatesRepository): from gns3server.controller import Controller 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: for builtin_template in BUILTIN_TEMPLATES: @@ -241,6 +245,8 @@ async def create_template(self, template_create: schemas.TemplateCreate) -> dict except pydantic.ValidationError as 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) db_template = await self._templates_repo.create_template(template_create.template_type, template_settings) for image in images_to_add_to_template: diff --git a/tests/api/routes/controller/test_templates.py b/tests/api/routes/controller/test_templates.py index 1a096d5fe..e66e5df65 100644 --- a/tests/api/routes/controller/test_templates.py +++ b/tests/api/routes/controller/test_templates.py @@ -18,6 +18,7 @@ import os import pytest import uuid +import unittest.mock from pathlib import Path from fastapi import FastAPI, status @@ -313,7 +314,7 @@ async def test_c7200_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 512, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -358,7 +359,7 @@ async def test_c3745_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 256, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -403,7 +404,7 @@ async def test_c3725_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 128, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -450,7 +451,7 @@ async def test_c3600_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 192, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -507,7 +508,7 @@ async def test_c2691_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 192, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -554,7 +555,7 @@ async def test_c2600_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 160, "sparsemem": True, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -613,7 +614,7 @@ async def test_c1700_dynamips_template_create(self, app: FastAPI, client: AsyncC "ram": 160, "sparsemem": False, "startup_config": "ios_base_startup-config.txt", - "symbol": ":/symbols/router.svg", + "symbol": unittest.mock.ANY, "system_id": "FTX0945W0MY"} for item, value in expected_response.items(): @@ -674,7 +675,7 @@ async def test_iou_template_create(self, app: FastAPI, client: AsyncClient) -> N "ram": 256, "serial_adapters": 2, "startup_config": "iou_l3_base_startup-config.txt", - "symbol": ":/symbols/multilayer_switch.svg", + "symbol": unittest.mock.ANY, "use_default_iou_values": True, "l1_keepalives": False} @@ -711,7 +712,7 @@ async def test_docker_template_create(self, app: FastAPI, client: AsyncClient) - "image": "gns3/endhost:latest", "name": "Docker template", "start_command": "", - "symbol": ":/symbols/docker_guest.svg", + "symbol": unittest.mock.ANY, "custom_adapters": []} for item, value in expected_response.items(): @@ -772,7 +773,7 @@ async def test_qemu_template_create(self, app: FastAPI, client: AsyncClient) -> "process_priority": "normal", "qemu_path": "", "ram": 512, - "symbol": ":/symbols/qemu_guest.svg", + "symbol": unittest.mock.ANY, "usage": "", "custom_adapters": []} @@ -810,7 +811,7 @@ async def test_vmware_template_create(self, app: FastAPI, client: AsyncClient) - "on_close": "power_off", "port_name_format": "Ethernet{0}", "port_segment_size": 0, - "symbol": ":/symbols/vmware_guest.svg", + "symbol": unittest.mock.ANY, "use_any_adapter": False, "vmx_path": vmx_path, "custom_adapters": []} @@ -849,7 +850,7 @@ async def test_virtualbox_template_create(self, app: FastAPI, client: AsyncClien "port_name_format": "Ethernet{0}", "port_segment_size": 0, "ram": 256, - "symbol": ":/symbols/vbox_guest.svg", + "symbol": unittest.mock.ANY, "use_any_adapter": False, "vmname": "My VirtualBox VM", "custom_adapters": []} @@ -879,7 +880,7 @@ async def test_vpcs_template_create(self, app: FastAPI, client: AsyncClient) -> "console_type": "telnet", "default_name_format": "PC{0}", "name": "VPCS template", - "symbol": ":/symbols/vpcs_guest.svg"} + "symbol": unittest.mock.ANY} for item, value in expected_response.items(): assert response.json().get(item) == value @@ -952,7 +953,7 @@ async def test_ethernet_switch_template_create(self, app: FastAPI, client: Async "type": "access", "vlan": 1 }], - "symbol": ":/symbols/ethernet_switch.svg"} + "symbol": unittest.mock.ANY} for item, value in expected_response.items(): assert response.json().get(item) == value @@ -995,7 +996,7 @@ async def test_ethernet_hub_template_create(self, app: FastAPI, client: AsyncCli }], "compute_id": "local", "name": "Ethernet hub template", - "symbol": ":/symbols/hub.svg", + "symbol": unittest.mock.ANY, "default_name_format": "Hub{0}", "template_type": "ethernet_hub", "category": "switch", @@ -1024,7 +1025,7 @@ async def test_cloud_template_create(self, app: FastAPI, client: AsyncClient) -> "default_name_format": "Cloud{0}", "name": "Cloud template", "ports_mapping": [], - "symbol": ":/symbols/cloud.svg", + "symbol": unittest.mock.ANY, "remote_console_host": "127.0.0.1", "remote_console_port": 23, "remote_console_type": "none", diff --git a/tests/controller/test_symbols.py b/tests/controller/test_symbols.py index b4bac254a..17966193d 100644 --- a/tests/controller/test_symbols.py +++ b/tests/controller/test_symbols.py @@ -17,8 +17,8 @@ import os - from gns3server.controller.symbols import Symbols +from gns3server.controller.symbol_themes import BUILTIN_SYMBOL_THEMES 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") +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(): symbols = Symbols() From 72eb13d94192baca3c2443f25023462aa95e9d84 Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 25 Jul 2022 20:22:12 +0200 Subject: [PATCH 2/3] Allow default symbol theme to be configured --- conf/gns3_server.conf | 5 +++++ gns3server/controller/symbols.py | 7 +++++-- gns3server/schemas/config.py | 12 ++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/conf/gns3_server.conf b/conf/gns3_server.conf index d4b94a1b6..d1143eb43 100644 --- a/conf/gns3_server.conf +++ b/conf/gns3_server.conf @@ -49,6 +49,11 @@ symbols_path = /home/gns3/GNS3/symbols ; Path where custom configs are stored 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 report_errors = True diff --git a/gns3server/controller/symbols.py b/gns3server/controller/symbols.py index 11fbc35c2..053d0ab34 100644 --- a/gns3server/controller/symbols.py +++ b/gns3server/controller/symbols.py @@ -43,7 +43,9 @@ def __init__(self): # Keep a cache of symbols size self._symbol_size_cache = {} - self._current_theme = "Affinity-square-blue" + + self._server_config = Config.instance().settings.Server + self._current_theme = self._server_config.default_symbol_theme self._themes = BUILTIN_SYMBOL_THEMES @property @@ -66,7 +68,8 @@ def get_default_symbol(self, symbol, symbol_theme): theme = self._themes.get(symbol_theme, None) if not theme: - raise ControllerNotFoundError(f"Could not find symbol theme '{symbol_theme}'") + log.warning(f"Could not find symbol theme '{self._current_theme}'") + return None symbol_path = theme.get(symbol) if symbol_path not in self._symbols_path: log.warning(f"Default symbol {symbol} was not found") diff --git a/gns3server/schemas/config.py b/gns3server/schemas/config.py index 9d4aae97d..d2efdcc0f 100644 --- a/gns3server/schemas/config.py +++ b/gns3server/schemas/config.py @@ -109,6 +109,17 @@ class ServerProtocol(str, Enum): 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): local: bool = False @@ -124,6 +135,7 @@ class ServerSettings(BaseModel): appliances_path: str = "~/GNS3/appliances" symbols_path: str = "~/GNS3/symbols" configs_path: str = "~/GNS3/configs" + default_symbol_theme: BuiltinSymbolTheme = BuiltinSymbolTheme.affinity_square_blue report_errors: bool = True additional_images_paths: List[str] = Field(default_factory=list) console_start_port_range: int = Field(5000, gt=0, le=65535) From 6d0c3753234b5ce166feefc5501e7075b59f9a8b Mon Sep 17 00:00:00 2001 From: grossmj Date: Mon, 25 Jul 2022 20:39:03 +0200 Subject: [PATCH 3/3] Use default symbol theme if none is provided when loading appliances --- gns3server/api/routes/controller/appliances.py | 4 ++-- gns3server/controller/appliance_manager.py | 4 +++- gns3server/controller/symbols.py | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/gns3server/api/routes/controller/appliances.py b/gns3server/api/routes/controller/appliances.py index 05fba4ada..c27f5a8f3 100644 --- a/gns3server/api/routes/controller/appliances.py +++ b/gns3server/api/routes/controller/appliances.py @@ -47,7 +47,7 @@ @router.get("") async def get_appliances( update: Optional[bool] = False, - symbol_theme: Optional[str] = "Classic" + symbol_theme: Optional[str] = None ) -> List[schemas.Appliance]: """ Return all appliances known by the controller. @@ -56,7 +56,7 @@ async def get_appliances( controller = Controller.instance() if update: 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()] diff --git a/gns3server/controller/appliance_manager.py b/gns3server/controller/appliance_manager.py index e4bc72f1e..855331065 100644 --- a/gns3server/controller/appliance_manager.py +++ b/gns3server/controller/appliance_manager.py @@ -281,7 +281,7 @@ async def install_appliance( template_data = await self._appliance_to_template(appliance) 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. """ @@ -326,6 +326,8 @@ def _get_default_symbol(self, appliance: dict, symbol_theme: str) -> str: from . import Controller controller = Controller.instance() + if not symbol_theme: + symbol_theme = controller.symbols.theme category = appliance["category"] if category == "guest": if "docker" in appliance: diff --git a/gns3server/controller/symbols.py b/gns3server/controller/symbols.py index 053d0ab34..b725c7c09 100644 --- a/gns3server/controller/symbols.py +++ b/gns3server/controller/symbols.py @@ -68,7 +68,7 @@ def get_default_symbol(self, symbol, symbol_theme): theme = self._themes.get(symbol_theme, None) if not theme: - log.warning(f"Could not find symbol theme '{self._current_theme}'") + log.warning(f"Could not find symbol theme '{symbol_theme}'") return None symbol_path = theme.get(symbol) if symbol_path not in self._symbols_path: