From e12e6044dc0521b7fc6169bcf42feebc20878fb2 Mon Sep 17 00:00:00 2001 From: Julien Duponchelle Date: Thu, 22 Jan 2015 11:34:10 +0100 Subject: [PATCH] Delete VPCS --- gns3server/handlers/vpcs_handler.py | 15 ++++++++++++++- gns3server/modules/base_manager.py | 15 +++++++++++++++ gns3server/modules/vpcs/vpcs_vm.py | 6 ++++++ tests/api/test_vpcs.py | 7 +++++++ tests/modules/vpcs/test_vpcs_vm.py | 11 +++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/gns3server/handlers/vpcs_handler.py b/gns3server/handlers/vpcs_handler.py index 18e69709..e97e24bc 100644 --- a/gns3server/handlers/vpcs_handler.py +++ b/gns3server/handlers/vpcs_handler.py @@ -74,6 +74,7 @@ class VPCSHandler: r"/vpcs/{uuid}", status_codes={ 200: "VPCS instance updated", + 404: "VPCS instance doesn't exist", 409: "Conflict" }, description="Update a VPCS instance", @@ -87,9 +88,21 @@ class VPCSHandler: vm.console = request.json.get("console", vm.console) vm.script_file = request.json.get("script_file", vm.script_file) vm.startup_script = request.json.get("startup_script", vm.startup_script) - response.json(vm) + @classmethod + @Route.delete( + r"/vpcs/{uuid}", + status_codes={ + 204: "VPCS instance updated", + 404: "VPCS instance doesn't exist" + }, + description="Delete a VPCS instance") + def delete(request, response): + + yield from VPCS.instance().delete_vm(request.match_info["uuid"]) + response.set_status(204) + @classmethod @Route.post( r"/vpcs/{uuid}/start", diff --git a/gns3server/modules/base_manager.py b/gns3server/modules/base_manager.py index 402b9422..992a1b29 100644 --- a/gns3server/modules/base_manager.py +++ b/gns3server/modules/base_manager.py @@ -132,3 +132,18 @@ class BaseManager: vm.create() self._vms[vm.uuid] = vm return vm + + @asyncio.coroutine + def delete_vm(self, uuid): + """ + Delete a VM + + :param uuid: VM UUID + """ + + vm = self.get_vm(uuid) + if asyncio.iscoroutinefunction(vm.destroy): + yield from vm.destroy() + else: + vm.destroy() + del self._vms[vm.uuid] diff --git a/gns3server/modules/vpcs/vpcs_vm.py b/gns3server/modules/vpcs/vpcs_vm.py index 8b43d9d0..d7ef3d3c 100644 --- a/gns3server/modules/vpcs/vpcs_vm.py +++ b/gns3server/modules/vpcs/vpcs_vm.py @@ -82,7 +82,13 @@ class VPCSVM(BaseVM): self._console = self._manager.port_manager.get_free_console_port() def __del__(self): + self.destroy() + + def destroy(self): self._kill_process() + if self._console: + self._manager.port_manager.release_console_port(self._console) + self._console = None @asyncio.coroutine def _check_requirements(self): diff --git a/tests/api/test_vpcs.py b/tests/api/test_vpcs.py index e8b61981..3c59c585 100644 --- a/tests/api/test_vpcs.py +++ b/tests/api/test_vpcs.py @@ -126,6 +126,13 @@ def test_vpcs_reload(server, vm): assert response.status == 204 +def test_vpcs_delete(server, vm): + with asyncio_patch("gns3server.modules.vpcs.VPCS.delete_vm", return_value=True) as mock: + response = server.delete("/vpcs/{}".format(vm["uuid"])) + assert mock.called + assert response.status == 204 + + def test_vpcs_update(server, vm, tmpdir, free_console_port): path = os.path.join(str(tmpdir), 'startup2.vpcs') with open(path, 'w+') as f: diff --git a/tests/modules/vpcs/test_vpcs_vm.py b/tests/modules/vpcs/test_vpcs_vm.py index c7c8518f..f3ac4dc3 100644 --- a/tests/modules/vpcs/test_vpcs_vm.py +++ b/tests/modules/vpcs/test_vpcs_vm.py @@ -177,3 +177,14 @@ def test_change_script_file(vm, tmpdir): path = os.path.join(str(tmpdir), 'startup2.vpcs') vm.script_file = path assert vm.script_file == path + + +def test_destroy(vm, port_manager): + with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM._check_requirements", return_value=True): + with asyncio_patch("asyncio.create_subprocess_exec", return_value=MagicMock()): + vm.start() + port = vm.console + vm.destroy() + # Raise an exception if the port is not free + port_manager.reserve_console_port(port) + assert vm.is_running() is False