mirror of
https://github.com/GNS3/gns3-server
synced 2024-12-25 00:08:11 +00:00
Merge branch 'master' into unstable
This commit is contained in:
commit
c50c735e86
@ -115,6 +115,43 @@ class Dynamips(BaseManager):
|
|||||||
self._devices = {}
|
self._devices = {}
|
||||||
self._ghost_files = set()
|
self._ghost_files = set()
|
||||||
self._dynamips_path = None
|
self._dynamips_path = None
|
||||||
|
self._dynamips_ids = {}
|
||||||
|
|
||||||
|
def get_dynamips_id(self, project_id):
|
||||||
|
"""
|
||||||
|
:param project_id: UUID of the project
|
||||||
|
:returns: a free dynamips id
|
||||||
|
"""
|
||||||
|
self._dynamips_ids.setdefault(project_id, set())
|
||||||
|
dynamips_id = 0
|
||||||
|
for dynamips_id in range(1, 4097):
|
||||||
|
if dynamips_id not in self._dynamips_ids[project_id]:
|
||||||
|
self._dynamips_ids[project_id].add(dynamips_id)
|
||||||
|
return dynamips_id
|
||||||
|
raise DynamipsError("Maximum number of Dynamips instances reached")
|
||||||
|
|
||||||
|
def take_dynamips_id(self, project_id, dynamips_id):
|
||||||
|
"""
|
||||||
|
Reserve a dynamips id or raise an error
|
||||||
|
|
||||||
|
:param project_id: UUID of the project
|
||||||
|
:param dynamips_id: Asked id
|
||||||
|
"""
|
||||||
|
self._dynamips_ids.setdefault(project_id, set())
|
||||||
|
if dynamips_id in self._dynamips_ids[project_id]:
|
||||||
|
raise DynamipsError("Dynamips identifier {} is already used by another router".format(dynamips_id))
|
||||||
|
self._dynamips_ids[project_id].add(dynamips_id)
|
||||||
|
|
||||||
|
def release_dynamips_id(self, project_id, dynamips_id):
|
||||||
|
"""
|
||||||
|
A dynamips id can be reused by another vm
|
||||||
|
|
||||||
|
:param project_id: UUID of the project
|
||||||
|
:param dynamips_id: Asked id
|
||||||
|
"""
|
||||||
|
self._dynamips_ids.setdefault(project_id, set())
|
||||||
|
if dynamips_id in self._dynamips_ids[project_id]:
|
||||||
|
self._dynamips_ids[project_id].remove(dynamips_id)
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def unload(self):
|
def unload(self):
|
||||||
@ -164,15 +201,15 @@ class Dynamips(BaseManager):
|
|||||||
|
|
||||||
:param project: Project instance
|
:param project: Project instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
yield from super().project_closed(project)
|
yield from super().project_closed(project)
|
||||||
# delete useless Dynamips files
|
# delete useless Dynamips files
|
||||||
project_dir = project.module_working_path(self.module_name.lower())
|
project_dir = project.module_working_path(self.module_name.lower())
|
||||||
files = glob.glob(glob.escape(os.path.join(project_dir, "*.ghost")))
|
|
||||||
files += glob.glob(glob.escape(os.path.join(project_dir, "*_lock")))
|
files = glob.glob(os.path.join(glob.escape(project_dir), "*.ghost"))
|
||||||
files += glob.glob(glob.escape(os.path.join(project_dir, "ilt_*")))
|
files += glob.glob(os.path.join(glob.escape(project_dir), "*_lock"))
|
||||||
files += glob.glob(glob.escape(os.path.join(project_dir, "c[0-9][0-9][0-9][0-9]_i[0-9]*_rommon_vars")))
|
files += glob.glob(os.path.join(glob.escape(project_dir), "ilt_*"))
|
||||||
files += glob.glob(glob.escape(os.path.join(project_dir, "c[0-9][0-9][0-9][0-9]_i[0-9]*_log.txt")))
|
files += glob.glob(os.path.join(glob.escape(project_dir), "c[0-9][0-9][0-9][0-9]_i[0-9]*_rommon_vars"))
|
||||||
|
files += glob.glob(os.path.join(glob.escape(project_dir), "c[0-9][0-9][0-9][0-9]_i[0-9]*_log.txt"))
|
||||||
for file in files:
|
for file in files:
|
||||||
try:
|
try:
|
||||||
log.debug("Deleting file {}".format(file))
|
log.debug("Deleting file {}".format(file))
|
||||||
@ -183,6 +220,11 @@ class Dynamips(BaseManager):
|
|||||||
log.warn("Could not delete file {}: {}".format(file, e))
|
log.warn("Could not delete file {}: {}".format(file, e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
# Release the dynamips ids if we want to reload the same project
|
||||||
|
# later
|
||||||
|
if project.id in self._dynamips_ids:
|
||||||
|
del self._dynamips_ids[project.id]
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def project_moved(self, project):
|
def project_moved(self, project):
|
||||||
"""
|
"""
|
||||||
|
@ -54,7 +54,6 @@ class Router(BaseVM):
|
|||||||
:param platform: Platform of this router
|
:param platform: Platform of this router
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_dynamips_ids = {}
|
|
||||||
_status = {0: "inactive",
|
_status = {0: "inactive",
|
||||||
1: "shutting down",
|
1: "shutting down",
|
||||||
2: "running",
|
2: "running",
|
||||||
@ -96,20 +95,11 @@ class Router(BaseVM):
|
|||||||
self._ghost_flag = ghost_flag
|
self._ghost_flag = ghost_flag
|
||||||
|
|
||||||
if not ghost_flag:
|
if not ghost_flag:
|
||||||
self._dynamips_ids.setdefault(project.id, list())
|
|
||||||
if not dynamips_id:
|
if not dynamips_id:
|
||||||
# find a Dynamips ID if none is provided (0 < id <= 4096)
|
self._dynamips_id = manager.get_dynamips_id(project.id)
|
||||||
self._dynamips_id = 0
|
|
||||||
for identifier in range(1, 4097):
|
|
||||||
if identifier not in self._dynamips_ids[project.id]:
|
|
||||||
self._dynamips_id = identifier
|
|
||||||
break
|
|
||||||
if self._dynamips_id == 0:
|
|
||||||
raise DynamipsError("Maximum number of Dynamips instances reached")
|
|
||||||
else:
|
else:
|
||||||
if dynamips_id in self._dynamips_ids[project.id]:
|
self._dynamips_id = dynamips_id
|
||||||
raise DynamipsError("Dynamips identifier {} is already used by another router".format(dynamips_id))
|
manager.take_dynamips_id(project.id, dynamips_id)
|
||||||
self._dynamips_ids[project.id].append(self._dynamips_id)
|
|
||||||
|
|
||||||
if self._aux is not None:
|
if self._aux is not None:
|
||||||
self._aux = self._manager.port_manager.reserve_tcp_port(self._aux, self._project)
|
self._aux = self._manager.port_manager.reserve_tcp_port(self._aux, self._project)
|
||||||
@ -1626,8 +1616,7 @@ class Router(BaseVM):
|
|||||||
log.warn("Could not delete file {}: {}".format(file, e))
|
log.warn("Could not delete file {}: {}".format(file, e))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if self._dynamips_id in self._dynamips_ids[self._project.id]:
|
self.manager.release_dynamips_id(self._project.id, self._dynamips_id)
|
||||||
self._dynamips_ids[self._project.id].remove(self._dynamips_id)
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def clean_delete(self):
|
def clean_delete(self):
|
||||||
|
@ -19,6 +19,9 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import tempfile
|
import tempfile
|
||||||
import sys
|
import sys
|
||||||
|
import uuid
|
||||||
|
import os
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from gns3server.modules.dynamips import Dynamips
|
from gns3server.modules.dynamips import Dynamips
|
||||||
from gns3server.modules.dynamips.dynamips_error import DynamipsError
|
from gns3server.modules.dynamips.dynamips_error import DynamipsError
|
||||||
@ -44,3 +47,50 @@ def test_vm_non_executable_dynamips_path(manager):
|
|||||||
with patch("gns3server.config.Config.get_section_config", return_value={"dynamips_path": tmpfile.name}):
|
with patch("gns3server.config.Config.get_section_config", return_value={"dynamips_path": tmpfile.name}):
|
||||||
with pytest.raises(DynamipsError):
|
with pytest.raises(DynamipsError):
|
||||||
manager.find_dynamips()
|
manager.find_dynamips()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_dynamips_id(manager):
|
||||||
|
project_1 = str(uuid.uuid4())
|
||||||
|
project_2 = str(uuid.uuid4())
|
||||||
|
project_3 = str(uuid.uuid4())
|
||||||
|
|
||||||
|
assert manager.get_dynamips_id(project_1) == 1
|
||||||
|
assert manager.get_dynamips_id(project_1) == 2
|
||||||
|
assert manager.get_dynamips_id(project_2) == 1
|
||||||
|
with pytest.raises(DynamipsError):
|
||||||
|
for dynamips_id in range(1, 4098):
|
||||||
|
manager.get_dynamips_id(project_3)
|
||||||
|
|
||||||
|
|
||||||
|
def test_take_dynamips_id(manager):
|
||||||
|
project_1 = str(uuid.uuid4())
|
||||||
|
|
||||||
|
manager.take_dynamips_id(project_1, 1)
|
||||||
|
assert manager.get_dynamips_id(project_1) == 2
|
||||||
|
with pytest.raises(DynamipsError):
|
||||||
|
manager.take_dynamips_id(project_1, 1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_release_dynamips_id(manager):
|
||||||
|
project_1 = str(uuid.uuid4())
|
||||||
|
project_2 = str(uuid.uuid4())
|
||||||
|
|
||||||
|
manager.take_dynamips_id(project_1, 1)
|
||||||
|
manager.release_dynamips_id(project_1, 1)
|
||||||
|
assert manager.get_dynamips_id(project_1) == 1
|
||||||
|
# Should not crash for 0 id
|
||||||
|
manager.release_dynamips_id(project_2, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_project_closed(manager, project, loop):
|
||||||
|
|
||||||
|
manager._dynamips_ids[project.id] = set([1, 2, 3])
|
||||||
|
|
||||||
|
project_dir = project.module_working_path(manager.module_name.lower())
|
||||||
|
os.makedirs(project_dir)
|
||||||
|
open(os.path.join(project_dir, "test.ghost"), "w+").close()
|
||||||
|
|
||||||
|
loop.run_until_complete(asyncio.async(manager.project_closed(project)))
|
||||||
|
|
||||||
|
assert not os.path.exists(os.path.join(project_dir, "test.ghost"))
|
||||||
|
assert project.id not in manager._dynamips_ids
|
||||||
|
Loading…
Reference in New Issue
Block a user