diff --git a/gns3server/controller/node.py b/gns3server/controller/node.py index c50aad9f..a992fe42 100644 --- a/gns3server/controller/node.py +++ b/gns3server/controller/node.py @@ -650,14 +650,14 @@ class Node: elif self._node_type in ("ethernet_switch", "ethernet_hub"): # Basic node we don't want to have adapter number port_number = 0 - for port in self._properties["ports_mapping"]: + for port in self._properties.get("ports_mapping", []): self._ports.append(PortFactory(port["name"], 0, 0, port_number, "ethernet", short_name="e{}".format(port_number))) port_number += 1 elif self._node_type in ("vpcs", "traceng"): self._ports.append(PortFactory("Ethernet0", 0, 0, 0, "ethernet", short_name="e0")) elif self._node_type in ("cloud", "nat"): port_number = 0 - for port in self._properties["ports_mapping"]: + for port in self._properties.get("ports_mapping", []): self._ports.append(PortFactory(port["name"], 0, 0, port_number, "ethernet", short_name=port["name"])) port_number += 1 else: diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index c8bbd45e..ad058832 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -503,7 +503,11 @@ class Project: template["x"] = x template["y"] = y node_type = template.pop("template_type") - compute = self.controller.get_compute(template.pop("compute_id", compute_id)) + if template["builtin"] is True: + # compute_id is selected by clients for builtin templates + compute = self.controller.get_compute(compute_id) + else: + compute = self.controller.get_compute(template.pop("compute_id", compute_id)) name = template.pop("name") default_name_format = template.pop("default_name_format", "{name}-{0}") name = default_name_format.replace("{name}", name) diff --git a/gns3server/controller/template.py b/gns3server/controller/template.py index 9d2b6bd8..968acd97 100644 --- a/gns3server/controller/template.py +++ b/gns3server/controller/template.py @@ -203,7 +203,11 @@ class Template: settings.update({"template_id": self._id, "builtin": self.builtin}) - if not self.builtin: + if self.builtin: + # builin templates have compute_id set to None to tell clients + # to select a compute + settings["compute_id"] = None + else: settings["compute_id"] = self.compute_id return settings diff --git a/gns3server/controller/template_manager.py b/gns3server/controller/template_manager.py index 63239fde..1af13be6 100644 --- a/gns3server/controller/template_manager.py +++ b/gns3server/controller/template_manager.py @@ -60,13 +60,13 @@ class TemplateManager: # Add builtins builtins = [] - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "cloud"), {"template_type": "cloud", "name": "Cloud", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True)) - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "nat"), {"template_type": "nat", "name": "NAT", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "cloud"), {"template_type": "cloud", "name": "Cloud", "default_name_format": "Cloud-{0}", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "nat"), {"template_type": "nat", "name": "NAT", "default_name_format": "NAT-{0}", "category": 2, "symbol": ":/symbols/cloud.svg"}, builtin=True)) builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "vpcs"), {"template_type": "vpcs", "name": "VPCS", "default_name_format": "PC-{0}", "category": 2, "symbol": ":/symbols/vpcs_guest.svg", "properties": {"base_script_file": "vpcs_base_config.txt"}}, builtin=True)) - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_switch"), {"template_type": "ethernet_switch", "console_type": "none", "name": "Ethernet switch", "category": 1, "symbol": ":/symbols/ethernet_switch.svg"}, builtin=True)) - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_hub"), {"template_type": "ethernet_hub", "name": "Ethernet hub", "category": 1, "symbol": ":/symbols/hub.svg"}, builtin=True)) - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "frame_relay_switch"), {"template_type": "frame_relay_switch", "name": "Frame Relay switch", "category": 1, "symbol": ":/symbols/frame_relay_switch.svg"}, builtin=True)) - builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "atm_switch"), {"template_type": "atm_switch", "name": "ATM switch", "category": 1, "symbol": ":/symbols/atm_switch.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_switch"), {"template_type": "ethernet_switch", "console_type": "none", "name": "Ethernet switch", "default_name_format": "Switch-{0}", "category": 1, "symbol": ":/symbols/ethernet_switch.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "ethernet_hub"), {"template_type": "ethernet_hub", "name": "Ethernet hub", "default_name_format": "Hub-{0}", "category": 1, "symbol": ":/symbols/hub.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "frame_relay_switch"), {"template_type": "frame_relay_switch", "name": "Frame Relay switch", "default_name_format": "FRSW-{0}", "category": 1, "symbol": ":/symbols/frame_relay_switch.svg"}, builtin=True)) + builtins.append(Template(uuid.uuid3(uuid.NAMESPACE_DNS, "atm_switch"), {"template_type": "atm_switch", "name": "ATM switch", "default_name_format": "ATMSW-{0}", "category": 1, "symbol": ":/symbols/atm_switch.svg"}, builtin=True)) #FIXME: disable TraceNG #if sys.platform.startswith("win"): diff --git a/gns3server/schemas/ethernet_hub_template.py b/gns3server/schemas/ethernet_hub_template.py index f7a5edcd..221ed68b 100644 --- a/gns3server/schemas/ethernet_hub_template.py +++ b/gns3server/schemas/ethernet_hub_template.py @@ -68,7 +68,7 @@ ETHERNET_HUB_TEMPLATE_PROPERTIES = { ETHERNET_HUB_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) ETHERNET_HUB_TEMPLATE_PROPERTIES["category"]["default"] = "switch" -ETHERNET_HUB_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Hub{0}" +ETHERNET_HUB_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Hub-{0}" ETHERNET_HUB_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/hub.svg" ETHERNET_HUB_TEMPLATE_OBJECT_SCHEMA = { diff --git a/gns3server/schemas/ethernet_switch_template.py b/gns3server/schemas/ethernet_switch_template.py index e2473220..1bd2680f 100644 --- a/gns3server/schemas/ethernet_switch_template.py +++ b/gns3server/schemas/ethernet_switch_template.py @@ -115,7 +115,7 @@ ETHERNET_SWITCH_TEMPLATE_PROPERTIES = { ETHERNET_SWITCH_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) ETHERNET_SWITCH_TEMPLATE_PROPERTIES["category"]["default"] = "switch" -ETHERNET_SWITCH_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Switch{0}" +ETHERNET_SWITCH_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "Switch-{0}" ETHERNET_SWITCH_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/ethernet_switch.svg" ETHERNET_SWITCH_TEMPLATE_OBJECT_SCHEMA = { diff --git a/gns3server/schemas/template.py b/gns3server/schemas/template.py index 2914911f..e9d4cc1e 100644 --- a/gns3server/schemas/template.py +++ b/gns3server/schemas/template.py @@ -37,7 +37,7 @@ BASE_TEMPLATE_PROPERTIES = { }, "compute_id": { "description": "Compute identifier", - "type": "string" + "type": ["null", "string"] }, "default_name_format": { "description": "Default name format", diff --git a/gns3server/schemas/vpcs_template.py b/gns3server/schemas/vpcs_template.py index e0726b24..e6582b6b 100644 --- a/gns3server/schemas/vpcs_template.py +++ b/gns3server/schemas/vpcs_template.py @@ -40,7 +40,7 @@ VPCS_TEMPLATE_PROPERTIES = { VPCS_TEMPLATE_PROPERTIES.update(copy.deepcopy(BASE_TEMPLATE_PROPERTIES)) VPCS_TEMPLATE_PROPERTIES["category"]["default"] = "guest" -VPCS_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "PC{0}" +VPCS_TEMPLATE_PROPERTIES["default_name_format"]["default"] = "PC-{0}" VPCS_TEMPLATE_PROPERTIES["symbol"]["default"] = ":/symbols/vpcs_guest.svg" VPCS_TEMPLATE_OBJECT_SCHEMA = { diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index 5fcee71e..4daca8a3 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -236,6 +236,37 @@ def test_add_node_from_template(async_run, controller): project.emit_notification.assert_any_call("node.created", node.__json__()) +def test_add_builtin_node_from_template(async_run, controller): + """ + For a local server we send the project path + """ + compute = MagicMock() + compute.id = "local" + project = Project(controller=controller, name="Test") + project.emit_notification = MagicMock() + template = Template(str(uuid.uuid4()), { + "name": "Builtin-switch", + "template_type": "ethernet_switch", + }, builtin=True) + controller.template_manager.templates[template.id] = template + template.__json__() + controller._computes["local"] = compute + + response = MagicMock() + response.json = {"console": 2048} + compute.post = AsyncioMagicMock(return_value=response) + + node = async_run(project.add_node_from_template(template.id, x=23, y=12, compute_id="local")) + compute.post.assert_any_call('/projects', data={ + "name": project._name, + "project_id": project._id, + "path": project._path + }) + + assert compute in project._project_created_on_compute + project.emit_notification.assert_any_call("node.created", node.__json__()) + + def test_delete_node(async_run, controller): """ For a local server we send the project path