mirror of
https://github.com/GNS3/gns3-server
synced 2025-02-17 18:42:00 +00:00
Garbage collect VM when closing a project
This commit is contained in:
parent
66860655b9
commit
a9afaa028c
@ -121,11 +121,7 @@ class ProjectHandler:
|
|||||||
|
|
||||||
pm = ProjectManager.instance()
|
pm = ProjectManager.instance()
|
||||||
project = pm.get_project(request.match_info["project_id"])
|
project = pm.get_project(request.match_info["project_id"])
|
||||||
for module in MODULES:
|
|
||||||
yield from module.instance().project_closing(project)
|
|
||||||
yield from project.close()
|
yield from project.close()
|
||||||
for module in MODULES:
|
|
||||||
yield from module.instance().project_closed(project)
|
|
||||||
pm.remove_project(project.id)
|
pm.remove_project(project.id)
|
||||||
response.set_status(204)
|
response.set_status(204)
|
||||||
|
|
||||||
|
@ -255,7 +255,9 @@ class BaseManager:
|
|||||||
:param project: Project instance
|
:param project: Project instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
pass
|
for vm in project.vms:
|
||||||
|
if vm.id in self._vms:
|
||||||
|
del self._vms[vm.id]
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def project_moved(self, project):
|
def project_moved(self, project):
|
||||||
|
@ -143,6 +143,7 @@ class Dynamips(BaseManager):
|
|||||||
:param project: Project instance
|
:param project: Project instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
yield from super().project_closing(project)
|
||||||
# delete the Dynamips devices corresponding to the project
|
# delete the Dynamips devices corresponding to the project
|
||||||
tasks = []
|
tasks = []
|
||||||
for device in self._devices.values():
|
for device in self._devices.values():
|
||||||
@ -165,8 +166,9 @@ class Dynamips(BaseManager):
|
|||||||
:param project: Project instance
|
:param project: Project instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
yield from super().project_closed(project)
|
||||||
# delete useless Dynamips files
|
# delete useless Dynamips files
|
||||||
project_dir = project.module_working_directory(self.module_name.lower())
|
project_dir = project.module_working_path(self.module_name.lower())
|
||||||
files = glob.glob(os.path.join(project_dir, "*.ghost"))
|
files = glob.glob(os.path.join(project_dir, "*.ghost"))
|
||||||
files += glob.glob(os.path.join(project_dir, "*_lock"))
|
files += glob.glob(os.path.join(project_dir, "*_lock"))
|
||||||
files += glob.glob(os.path.join(project_dir, "ilt_*"))
|
files += glob.glob(os.path.join(project_dir, "ilt_*"))
|
||||||
|
@ -180,13 +180,21 @@ class Project:
|
|||||||
:returns: working directory
|
:returns: working directory
|
||||||
"""
|
"""
|
||||||
|
|
||||||
workdir = os.path.join(self._path, "project-files", module_name)
|
workdir = self.module_working_path(module_name)
|
||||||
try:
|
try:
|
||||||
os.makedirs(workdir, exist_ok=True)
|
os.makedirs(workdir, exist_ok=True)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
raise aiohttp.web.HTTPInternalServerError(text="Could not create module working directory: {}".format(e))
|
raise aiohttp.web.HTTPInternalServerError(text="Could not create module working directory: {}".format(e))
|
||||||
return workdir
|
return workdir
|
||||||
|
|
||||||
|
def module_working_path(self, module_name):
|
||||||
|
"""
|
||||||
|
Return the working direcotory for the module. If you want
|
||||||
|
to be sure to have the directory on disk take a look on:
|
||||||
|
module_working_directory
|
||||||
|
"""
|
||||||
|
return os.path.join(self._path, "project-files", module_name)
|
||||||
|
|
||||||
def vm_working_directory(self, vm):
|
def vm_working_directory(self, vm):
|
||||||
"""
|
"""
|
||||||
Return a working directory for a specific VM.
|
Return a working directory for a specific VM.
|
||||||
@ -250,7 +258,11 @@ class Project:
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""Close the project, but keep information on disk"""
|
"""Close the project, but keep information on disk"""
|
||||||
|
|
||||||
|
for module in self.modules():
|
||||||
|
yield from module.instance().project_closing(self)
|
||||||
yield from self._close_and_clean(self._temporary)
|
yield from self._close_and_clean(self._temporary)
|
||||||
|
for module in self.modules():
|
||||||
|
yield from module.instance().project_closed(self)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def _close_and_clean(self, cleanup):
|
def _close_and_clean(self, cleanup):
|
||||||
@ -304,7 +316,11 @@ class Project:
|
|||||||
def delete(self):
|
def delete(self):
|
||||||
"""Remove project from disk"""
|
"""Remove project from disk"""
|
||||||
|
|
||||||
|
for module in self.modules():
|
||||||
|
yield from module.instance().project_closing(self)
|
||||||
yield from self._close_and_clean(True)
|
yield from self._close_and_clean(True)
|
||||||
|
for module in self.modules():
|
||||||
|
yield from module.instance().project_closed(self)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def clean_project_directory(cls):
|
def clean_project_directory(cls):
|
||||||
@ -318,3 +334,10 @@ class Project:
|
|||||||
if os.path.exists(os.path.join(path, ".gns3_temporary")):
|
if os.path.exists(os.path.join(path, ".gns3_temporary")):
|
||||||
log.warning("Purge old temporary project {}".format(project))
|
log.warning("Purge old temporary project {}".format(project))
|
||||||
shutil.rmtree(path)
|
shutil.rmtree(path)
|
||||||
|
|
||||||
|
def modules(self):
|
||||||
|
"""Return VM modules loaded"""
|
||||||
|
|
||||||
|
# We import it at the last time to avoid circular dependencies
|
||||||
|
from ..modules import MODULES
|
||||||
|
return MODULES
|
||||||
|
@ -81,30 +81,3 @@ def test_create_vm_old_topology(loop, project, tmpdir, port_manager):
|
|||||||
vm_dir = os.path.join(project_dir, "project-files", "vpcs", vm.id)
|
vm_dir = os.path.join(project_dir, "project-files", "vpcs", vm.id)
|
||||||
with open(os.path.join(vm_dir, "startup.vpc")) as f:
|
with open(os.path.join(vm_dir, "startup.vpc")) as f:
|
||||||
assert f.read() == "1"
|
assert f.read() == "1"
|
||||||
|
|
||||||
|
|
||||||
# def test_create_vm_old_topology_with_garbage_in_project_dir(loop, project, tmpdir, port_manager):
|
|
||||||
#
|
|
||||||
# with patch("gns3server.config.Config.get_section_config", return_value={"local": True}):
|
|
||||||
# # Create an old topology directory
|
|
||||||
# project_dir = str(tmpdir / "testold")
|
|
||||||
# vm_dir = os.path.join(project_dir, "testold-files", "vpcs", "pc-1")
|
|
||||||
# project.path = project_dir
|
|
||||||
# os.makedirs(vm_dir, exist_ok=True)
|
|
||||||
# with open(os.path.join(vm_dir, "startup.vpc"), "w+") as f:
|
|
||||||
# f.write("1")
|
|
||||||
# with open(os.path.join(os.path.join(project_dir, "testold-files"), "crash.log"), "w+") as f:
|
|
||||||
# f.write("1")
|
|
||||||
#
|
|
||||||
# VPCS._instance = None
|
|
||||||
# vpcs = VPCS.instance()
|
|
||||||
# vpcs.port_manager = port_manager
|
|
||||||
# vm_id = 1
|
|
||||||
# vm = loop.run_until_complete(vpcs.create_vm("PC 1", project.id, vm_id))
|
|
||||||
# assert len(vm.id) == 36
|
|
||||||
#
|
|
||||||
# assert os.path.exists(os.path.join(project_dir, "testold-files")) is True
|
|
||||||
#
|
|
||||||
# vm_dir = os.path.join(project_dir, "project-files", "vpcs", vm.id)
|
|
||||||
# with open(os.path.join(vm_dir, "startup.vpc")) as f:
|
|
||||||
# assert f.read() == "1"
|
|
||||||
|
@ -184,9 +184,11 @@ def test_project_close(loop, manager):
|
|||||||
project = Project()
|
project = Project()
|
||||||
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
|
vm = VPCSVM("test", "00010203-0405-0607-0809-0a0b0c0d0e0f", project, manager)
|
||||||
project.add_vm(vm)
|
project.add_vm(vm)
|
||||||
|
vm.manager._vms = {vm.id: vm}
|
||||||
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM.close") as mock:
|
with asyncio_patch("gns3server.modules.vpcs.vpcs_vm.VPCSVM.close") as mock:
|
||||||
loop.run_until_complete(asyncio.async(project.close()))
|
loop.run_until_complete(asyncio.async(project.close()))
|
||||||
assert mock.called
|
assert mock.called
|
||||||
|
assert vm.id not in vm.manager._vms
|
||||||
|
|
||||||
|
|
||||||
def test_project_close_temporary_project(loop, manager):
|
def test_project_close_temporary_project(loop, manager):
|
||||||
|
Loading…
Reference in New Issue
Block a user