From 00ac2c19bddac57d26aa5090d3de7cc5b2e396cb Mon Sep 17 00:00:00 2001 From: Sanjay Santhanam <51058514+Sanjays2402@users.noreply.github.com> Date: Sat, 25 Jul 2026 20:00:43 -0700 Subject: [PATCH] Do not start nodes when deleting a project Project.delete() calls open() to rebuild the internal data structures needed for cleanup. open() schedules start_all() when the project has auto_start enabled, so deleting an auto-start project actually launched every node process, allocating ports and consuming resources, only for close() to kill them moments later. open() now takes an auto_start argument (default True, so normal opens are unchanged) and delete() passes auto_start=False. Fixes #2784 --- gns3server/controller/project.py | 9 ++++++--- tests/controller/test_project.py | 13 +++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/gns3server/controller/project.py b/gns3server/controller/project.py index f26b1ff5f..e35e89038 100644 --- a/gns3server/controller/project.py +++ b/gns3server/controller/project.py @@ -917,7 +917,7 @@ class Project: if self._status != "opened": try: - await self.open() + await self.open(auto_start=False) except aiohttp.web.HTTPConflict as e: # ignore missing images or other conflicts when deleting a project log.warning(f"Conflict while deleting project: {e}") @@ -998,9 +998,12 @@ class Project: return os.path.join(self.path, self._filename) @locking - async def open(self): + async def open(self, auto_start=True): """ Load topology elements + + :param auto_start: whether the nodes may be started when the project + has auto start enabled """ if self._closing: @@ -1114,7 +1117,7 @@ class Project: self._loading = False self.emit_controller_notification("project.opened", self.__json__()) # Should we start the nodes when project is open - if self._auto_start: + if self._auto_start and auto_start: # Start all in the background without waiting for completion # we ignore errors because we want to let the user open # their project and fix it diff --git a/tests/controller/test_project.py b/tests/controller/test_project.py index 234bf1b57..5d7d8a52a 100644 --- a/tests/controller/test_project.py +++ b/tests/controller/test_project.py @@ -655,6 +655,19 @@ async def test_delete(project): assert not os.path.exists(project.path) +async def test_delete_does_not_start_nodes(project): + """ + Deleting a project must not start its nodes, even when auto_start is enabled. + """ + + project.auto_start = True + project.dump() + await project.close() + project.start_all = AsyncioMagicMock() + await project.delete() + assert not project.start_all.called + + async def test_dump(projects_dir): directory = projects_dir