diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index ddb12e3b..f5bbfd7b 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -322,35 +322,43 @@ class Project: @open_required @asyncio.coroutine - def add_node(self, compute, name, node_id, **kwargs): + def add_node(self, compute, name, node_id, node_type=None, **kwargs): """ Create a node or return an existing node :param kwargs: See the documentation of node """ - if node_id not in self._nodes: - node = Node(self, compute, name, node_id=node_id, **kwargs) - if compute not in self._project_created_on_compute: - # For a local server we send the project path - if compute.id == "local": - yield from compute.post("/projects", data={ - "name": self._name, - "project_id": self._id, - "path": self._path - }) - else: - yield from compute.post("/projects", data={ - "name": self._name, - "project_id": self._id, - }) + if node_id in self._nodes: + return self._nodes[node_id] - self._project_created_on_compute.add(compute) - yield from node.create() - self._nodes[node.id] = node - self.controller.notification.emit("node.created", node.__json__()) - self.dump() - return node - return self._nodes[node_id] + # Due to a limitation all iou need to run on the same + # compute server otherwise you have mac address conflict + if node_type == "iou": + for node in self._nodes.values(): + if node.node_type == node_type and node.compute != compute: + raise aiohttp.web.HTTPConflict(text="All IOU nodes need to run on the same server.") + + node = Node(self, compute, name, node_id=node_id, node_type=node_type, **kwargs) + if compute not in self._project_created_on_compute: + # For a local server we send the project path + if compute.id == "local": + yield from compute.post("/projects", data={ + "name": self._name, + "project_id": self._id, + "path": self._path + }) + else: + yield from compute.post("/projects", data={ + "name": self._name, + "project_id": self._id, + }) + + self._project_created_on_compute.add(compute) + yield from node.create() + self._nodes[node.id] = node + self.controller.notification.emit("node.created", node.__json__()) + self.dump() + return node @open_required @asyncio.coroutine diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index ba554e4e..60ae678b 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -178,6 +178,28 @@ def test_add_node_non_local(async_run, controller): controller.notification.emit.assert_any_call("node.created", node.__json__()) +def test_create_iou_on_multiple_node(async_run, controller): + """ + Due to mac address collision you can't create an IOU node + on two different server + """ + compute = MagicMock() + compute.id = "remote" + + compute2 = MagicMock() + compute2.id = "remote2" + + project = Project(controller=controller, name="Test") + + response = MagicMock() + response.json = {"console": 2048} + compute.post = AsyncioMagicMock(return_value=response) + + node1 = async_run(project.add_node(compute, "test", None, node_type="iou")) + with pytest.raises(aiohttp.web_exceptions.HTTPConflict): + async_run(project.add_node(compute2, "test2", None, node_type="iou")) + + def test_delete_node(async_run, controller): """ For a local server we send the project path