From cf91e904f7316a66365882cd78711b6ed27b78bf Mon Sep 17 00:00:00 2001 From: grossmj Date: Tue, 12 Mar 2019 18:13:33 +0700 Subject: [PATCH] Early support for symbol themes. --- gns3server/controller/appliance.py | 4 ++++ gns3server/controller/appliance_manager.py | 24 +++++++++++++++++-- gns3server/controller/symbol_themes.py | 12 +++++----- gns3server/controller/symbols.py | 24 +++++++++++++------ .../api/controller/appliance_handler.py | 3 ++- .../handlers/api/controller/symbol_handler.py | 11 +++++++++ 6 files changed, 62 insertions(+), 16 deletions(-) diff --git a/gns3server/controller/appliance.py b/gns3server/controller/appliance.py index a04b8b38..aba9beb2 100644 --- a/gns3server/controller/appliance.py +++ b/gns3server/controller/appliance.py @@ -45,6 +45,10 @@ class Appliance: def symbol(self): return self._data.get("symbol") + @symbol.setter + def symbol(self, new_symbol): + self._data["symbol"] = new_symbol + def __json__(self): """ Appliance data (a hash) diff --git a/gns3server/controller/appliance_manager.py b/gns3server/controller/appliance_manager.py index 00819d83..17c7fd30 100644 --- a/gns3server/controller/appliance_manager.py +++ b/gns3server/controller/appliance_manager.py @@ -74,7 +74,7 @@ class ApplianceManager: os.makedirs(appliances_path, exist_ok=True) return appliances_path - def load_appliances(self): + def load_appliances(self, symbol_theme="Classic"): """ Loads appliance files from disk. """ @@ -90,13 +90,33 @@ class ApplianceManager: try: with open(path, 'r', encoding='utf-8') as f: appliance = Appliance(appliance_id, json.load(f), builtin=builtin) - appliance.__json__() # Check if loaded without error + json_data = appliance.__json__() # Check if loaded without error if appliance.status != 'broken': self._appliances[appliance.id] = appliance + if not appliance.symbol or appliance.symbol.startswith(":/symbols/"): + # apply a default symbol if the appliance has none or a default symbol + default_symbol = self._get_default_symbol(json_data, symbol_theme) + if default_symbol: + appliance.symbol = default_symbol except (ValueError, OSError, KeyError) as e: log.warning("Cannot load appliance file '%s': %s", path, str(e)) continue + def _get_default_symbol(self, appliance, symbol_theme): + """ + Returns the default symbol for a given appliance. + """ + + from . import Controller + controller = Controller.instance() + category = appliance["category"] + if category == "guest": + if "docker" in appliance: + return controller.symbols.get_default_symbol("docker_guest", symbol_theme) + elif "qemu" in appliance: + return controller.symbols.get_default_symbol("qemu_guest", symbol_theme) + return controller.symbols.get_default_symbol(category, symbol_theme) + async def download_custom_symbols(self): """ Download custom appliance symbols from our GitHub registry repository. diff --git a/gns3server/controller/symbol_themes.py b/gns3server/controller/symbol_themes.py index 876ad8df..68937ce6 100644 --- a/gns3server/controller/symbol_themes.py +++ b/gns3server/controller/symbol_themes.py @@ -37,7 +37,7 @@ AFFINITY_SQUARE_BLUE_SYMBOL_THEME = {"cloud": ":/symbols/affinity/square/blue/cl "frame_relay_switch.svg": ":/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/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/square/blue/switch_multilayer.svg", "firewall": ":/symbols/affinity/square/blue/firewall3.svg", "computer": ":/symbols/affinity/square/blue/client.svg", "vpcs_guest": ":/symbols/affinity/square/blue/client.svg", @@ -52,7 +52,7 @@ AFFINITY_SQUARE_RED_SYMBOL_THEME = {"cloud": ":/symbols/affinity/square/red/clou "frame_relay_switch": ":/symbols/affinity/square/red/isdn.svg", "atm_switch": ":/symbols/affinity/square/red/atm.svg", "router": ":/symbols/affinity/square/red/router.svg", - "multilayer_switch": ":/symbols/affinity/square/red/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/square/red/switch_multilayer.svg", "firewall": ":/symbols/affinity/square/red/firewall3.svg", "computer": ":/symbols/affinity/square/red/client.svg", "vpcs_guest": ":/symbols/affinity/square/red/client.svg", @@ -67,7 +67,7 @@ AFFINITY_SQUARE_GRAY_SYMBOL_THEME = {"cloud": ":/symbols/affinity/square/gray/cl "frame_relay_switch": ":/symbols/affinity/square/gray/isdn.svg", "atm_switch": ":/symbols/affinity/square/gray/atm.svg", "router": ":/symbols/affinity/square/gray/router.svg", - "multilayer_switch": ":/symbols/affinity/square/gray/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/square/gray/switch_multilayer.svg", "firewall": ":/symbols/affinity/square/gray/firewall3.svg", "computer": ":/symbols/affinity/square/gray/client.svg", "vpcs_guest": ":/symbols/affinity/square/gray/client.svg", @@ -82,7 +82,7 @@ AFFINITY_CIRCLE_BLUE_SYMBOL_THEME = {"cloud": ":/symbols/affinity/circle/blue/cl "frame_relay_switch": ":/symbols/affinity/circle/blue/isdn.svg", "atm_switch": ":/symbols/affinity/circle/blue/atm.svg", "router": ":/symbols/affinity/circle/blue/router.svg", - "multilayer_switch": ":/symbols/affinity/circle/blue/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/circle/blue/switch_multilayer.svg", "firewall": ":/symbols/affinity/circle/blue/firewall3.svg", "computer": ":/symbols/affinity/circle/blue/client.svg", "vpcs_guest": ":/symbols/affinity/circle/blue/client.svg", @@ -97,7 +97,7 @@ AFFINITY_CIRCLE_RED_SYMBOL_THEME = {"cloud": ":/symbols/affinity/circle/red/clou "frame_relay_switch": ":/symbols/affinity/circle/red/isdn.svg", "atm_switch": ":/symbols/affinity/circle/red/atm.svg", "router": ":/symbols/affinity/circle/red/router.svg", - "multilayer_switch": ":/symbols/affinity/circle/red/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/circle/red/switch_multilayer.svg", "firewall": ":/symbols/affinity/circle/red/firewall3.svg", "computer": ":/symbols/affinity/circle/red/client.svg", "vpcs_guest": ":/symbols/affinity/circle/red/client.svg", @@ -112,7 +112,7 @@ AFFINITY_CIRCLE_GRAY_SYMBOL_THEME = {"cloud": ":/symbols/affinity/circle/gray/cl "frame_relay_switch": ":/symbols/affinity/circle/gray/isdn.svg", "atm_switch": ":/symbols/affinity/circle/gray/atm.svg", "router": ":/symbols/affinity/circle/gray/router.svg", - "multilayer_switch": ":/symbols/affinity/circle/gray/multilayer_switch.svg", + "multilayer_switch": ":/symbols/affinity/circle/gray/switch_multilayer.svg", "firewall": ":/symbols/affinity/circle/gray/firewall3.svg", "computer": ":/symbols/affinity/circle/gray/client.svg", "vpcs_guest": ":/symbols/affinity/circle/gray/client.svg", diff --git a/gns3server/controller/symbols.py b/gns3server/controller/symbols.py index fc29ce47..595848c9 100644 --- a/gns3server/controller/symbols.py +++ b/gns3server/controller/symbols.py @@ -16,6 +16,7 @@ # along with this program. If not, see . import os +import aiohttp import posixpath from .symbol_themes import BUILTIN_SYMBOL_THEMES @@ -53,10 +54,24 @@ class Symbols: def theme(self, theme): if not self._themes.get(theme): - log.error("Could not find symbol theme '{}'".format(theme)) - return + raise aiohttp.web.HTTPNotFound(text="Could not find symbol theme '{}'".format(theme)) self._current_theme = theme + def default_symbols(self): + + return BUILTIN_SYMBOL_THEMES + + def get_default_symbol(self, symbol, symbol_theme): + + theme = self._themes.get(symbol_theme, None) + if not theme: + raise aiohttp.web.HTTPNotFound(text="Could not find symbol theme '{}'".format(symbol_theme)) + symbol_path = theme.get(symbol) + if symbol_path not in self._symbols_path: + log.warning("Default symbol {} was not found".format(symbol_path)) + return None + return symbol_path + def list(self): self._symbols_path = {} @@ -102,13 +117,8 @@ class Symbols: return directory def get_path(self, symbol_id): - #symbol_filename = os.path.splitext(os.path.basename(symbol_id))[0] - #theme = self._themes.get(self._current_theme, {}) - #if not theme: - # log.error("Could not find symbol theme '{}'".format(self._current_theme)) try: return self._symbols_path[symbol_id] - #return self._symbols_path[theme.get(symbol_filename, symbol_id)] except KeyError: try: self.list() diff --git a/gns3server/handlers/api/controller/appliance_handler.py b/gns3server/handlers/api/controller/appliance_handler.py index 178279e6..e8ceff84 100644 --- a/gns3server/handlers/api/controller/appliance_handler.py +++ b/gns3server/handlers/api/controller/appliance_handler.py @@ -38,5 +38,6 @@ class ApplianceHandler: controller = Controller.instance() if request.query.get("update", "no").lower() == "yes": await controller.appliance_manager.download_appliances() - controller.appliance_manager.load_appliances() + symbol_theme = request.query.get("symbol_theme", "Classic") + controller.appliance_manager.load_appliances(symbol_theme=symbol_theme) response.json([c for c in controller.appliance_manager.appliances.values()]) diff --git a/gns3server/handlers/api/controller/symbol_handler.py b/gns3server/handlers/api/controller/symbol_handler.py index 3b754379..a8a23e82 100644 --- a/gns3server/handlers/api/controller/symbol_handler.py +++ b/gns3server/handlers/api/controller/symbol_handler.py @@ -85,6 +85,17 @@ class SymbolHandler: controller.symbols.list() response.set_status(204) + @Route.get( + r"/default_symbols", + description="List of default symbols", + status_codes={ + 200: "Default symbols list returned" + }) + def list_default_symbols(request, response): + + controller = Controller.instance() + response.json(controller.symbols.default_symbols()) + # @Route.post( # r"/symbol_theme", # description="Create a new symbol theme",