diff --git a/gns3server/api/routes/index.py b/gns3server/api/routes/index.py index ebd22c096..365840b8c 100644 --- a/gns3server/api/routes/index.py +++ b/gns3server/api/routes/index.py @@ -52,7 +52,7 @@ async def web_ui(file_path: str): static = get_resource(file_path) - if static is None or not os.path.exists(static): + if static is None or not os.path.exists(static) or os.path.isdir(static): static = get_resource(os.path.join("static", "web-ui", "index.html")) if static is None: diff --git a/gns3server/api/server.py b/gns3server/api/server.py index 224a8314b..196ddb504 100644 --- a/gns3server/api/server.py +++ b/gns3server/api/server.py @@ -73,7 +73,7 @@ def get_application() -> FastAPI: application.include_router(index.router, tags=["Index"]) application.include_router(controller.router, prefix="/v3") - application.mount("/static", StaticFiles(packages=[('gns3server', 'static')]), name="static") + application.mount("/static", StaticFiles(packages=[('gns3server', 'static')], html=True), name="static") application.mount("/v3/compute", compute_api, name="compute") return application diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index bda44df78..3378f055f 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -539,6 +539,25 @@ class Node: del data[k] del self._properties[k] # We send the file only one time data["name"] = self._name + + # For remote computes, convert absolute image paths to relative paths + # The remote compute will search for the image in its own configured directories + if self._compute.id != "local": + # Image path fields for various node types + image_path_fields = { + # Common fields (IOU, Docker, etc.) + "path", "image", + # QEMU-specific fields + "hda_disk_image", "hdb_disk_image", "hdc_disk_image", "hdd_disk_image", + "cdrom_image", "bios_image", "initrd", "kernel_image", + # VMware-specific fields + "vmx_path", + } + + for field in image_path_fields: + if field in data and data[field] and os.path.isabs(data[field]): + data[field] = os.path.basename(data[field]) + if self._console: # console is optional for builtin nodes data["console"] = self._console diff --git a/gns3server/services/templates.py b/gns3server/services/templates.py index d2856c0d8..92b78633e 100644 --- a/gns3server/services/templates.py +++ b/gns3server/services/templates.py @@ -281,6 +281,14 @@ class TemplatesService: if not db_template: raise ControllerNotFoundError(f"Template '{template_id}' not found") + # Check for duplicate name (excluding current template) + if template_update.name is not None: + existing_template = await self._templates_repo.get_template_by_name_and_version( + template_update.name, db_template.version + ) + if existing_template and existing_template.template_id != template_id: + raise ControllerError(f"A template with name '{template_update.name}' already exists") + try: # validate the update settings update_settings = jsonable_encoder(template_update, exclude_unset=True)