diff --git a/gns3server/controller/link.py b/gns3server/controller/link.py index 6700babc..5eb25ccd 100644 --- a/gns3server/controller/link.py +++ b/gns3server/controller/link.py @@ -305,6 +305,13 @@ class Link: n["port"].link = None n["node"].remove_link(self) + async def reset(self): + """ + Reset a link + """ + + raise NotImplementedError + async def start_capture(self, data_link_type="DLT_EN10MB", capture_file_name=None): """ Start capture on the link diff --git a/gns3server/controller/udp_link.py b/gns3server/controller/udp_link.py index 97d4b916..7abab5dc 100644 --- a/gns3server/controller/udp_link.py +++ b/gns3server/controller/udp_link.py @@ -141,7 +141,7 @@ class UDPLink(Link): return try: await node1.delete("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number1, port_number=port_number1), timeout=120) - # If the node is already delete (user selected multiple element and delete all in the same time) + # If the node is already deleted (user selected multiple element and delete all in the same time) except aiohttp.web.HTTPNotFound: pass @@ -153,11 +153,20 @@ class UDPLink(Link): return try: await node2.delete("/adapters/{adapter_number}/ports/{port_number}/nio".format(adapter_number=adapter_number2, port_number=port_number2), timeout=120) - # If the node is already delete (user selected multiple element and delete all in the same time) + # If the node is already deleted (user selected multiple element and delete all in the same time) except aiohttp.web.HTTPNotFound: pass await super().delete() + async def reset(self): + """ + Reset the link. + """ + + # recreate the link on the compute + await self.delete() + await self.create() + async def start_capture(self, data_link_type="DLT_EN10MB", capture_file_name=None): """ Start capture on a link diff --git a/gns3server/handlers/api/controller/link_handler.py b/gns3server/handlers/api/controller/link_handler.py index 7854583a..17e6fa0f 100644 --- a/gns3server/handlers/api/controller/link_handler.py +++ b/gns3server/handlers/api/controller/link_handler.py @@ -200,6 +200,26 @@ class LinkHandler: await project.delete_link(request.match_info["link_id"]) response.set_status(204) + @Route.post( + r"/projects/{project_id}/links/{link_id}/reset", + parameters={ + "project_id": "Project UUID", + "link_id": "Link UUID" + }, + status_codes={ + 201: "Link reset", + 400: "Invalid request" + }, + description="Reset link instance", + output=LINK_OBJECT_SCHEMA) + async def reset(request, response): + + project = await Controller.instance().get_loaded_project(request.match_info["project_id"]) + link = project.get_link(request.match_info["link_id"]) + await link.reset() + response.set_status(201) + response.json(link) + @Route.get( r"/projects/{project_id}/links/{link_id}/pcap", parameters={ diff --git a/tests/handlers/api/controller/test_link.py b/tests/handlers/api/controller/test_link.py index be87b74b..5810b4e8 100644 --- a/tests/handlers/api/controller/test_link.py +++ b/tests/handlers/api/controller/test_link.py @@ -22,6 +22,7 @@ from tests.utils import asyncio_patch, AsyncioMagicMock from gns3server.controller.ports.ethernet_port import EthernetPort from gns3server.controller.link import Link, FILTERS +from gns3server.controller.udp_link import UDPLink @pytest.fixture @@ -295,6 +296,18 @@ async def test_list_link(controller_api, project, nodes): assert response.json[0]["filters"] == filters +async def test_reset_link(controller_api, project): + + link = UDPLink(project) + project._links = {link.id: link} + with asyncio_patch("gns3server.controller.udp_link.UDPLink.delete") as delete_mock: + with asyncio_patch("gns3server.controller.udp_link.UDPLink.create") as create_mock: + response = await controller_api.post("/projects/{}/links/{}/reset".format(project.id, link.id)) + assert delete_mock.called + assert create_mock.called + assert response.status == 201 + + async def test_start_capture(controller_api, project): link = Link(project)