mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-28 11:18:11 +00:00
Fix issue when running multiple project containing IOU nodes on the same server. Ref #1239.
This commit is contained in:
parent
1045364adc
commit
e5c76750b1
@ -25,6 +25,7 @@ import asyncio
|
|||||||
from ..base_manager import BaseManager
|
from ..base_manager import BaseManager
|
||||||
from .iou_error import IOUError
|
from .iou_error import IOUError
|
||||||
from .iou_vm import IOUVM
|
from .iou_vm import IOUVM
|
||||||
|
from .utils.application_id import get_next_application_id
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -38,8 +39,7 @@ class IOU(BaseManager):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._free_application_ids = list(range(1, 512))
|
self._iou_id_lock = asyncio.Lock()
|
||||||
self._used_application_ids = {}
|
|
||||||
|
|
||||||
@asyncio.coroutine
|
@asyncio.coroutine
|
||||||
def create_node(self, *args, **kwargs):
|
def create_node(self, *args, **kwargs):
|
||||||
@ -49,40 +49,14 @@ class IOU(BaseManager):
|
|||||||
:returns: IOUVM instance
|
:returns: IOUVM instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
node = yield from super().create_node(*args, **kwargs)
|
with (yield from self._iou_id_lock):
|
||||||
try:
|
# wait for a node to be completely created before adding a new one
|
||||||
self._used_application_ids[node.id] = self._free_application_ids.pop(0)
|
# this is important otherwise we allocate the same application ID
|
||||||
except IndexError:
|
# when creating multiple IOU node at the same time
|
||||||
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs reached on this host)")
|
application_id = get_next_application_id(self.nodes)
|
||||||
|
node = yield from super().create_node(*args, application_id=application_id, **kwargs)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
@asyncio.coroutine
|
|
||||||
def close_node(self, node_id, *args, **kwargs):
|
|
||||||
"""
|
|
||||||
Closes an IOU VM.
|
|
||||||
|
|
||||||
:returns: IOUVM instance
|
|
||||||
"""
|
|
||||||
|
|
||||||
node = self.get_node(node_id)
|
|
||||||
if node_id in self._used_application_ids:
|
|
||||||
i = self._used_application_ids[node_id]
|
|
||||||
self._free_application_ids.insert(0, i)
|
|
||||||
del self._used_application_ids[node_id]
|
|
||||||
yield from super().close_node(node_id, *args, **kwargs)
|
|
||||||
return node
|
|
||||||
|
|
||||||
def get_application_id(self, node_id):
|
|
||||||
"""
|
|
||||||
Get an unique application identifier for IOU.
|
|
||||||
|
|
||||||
:param node_id: Node identifier
|
|
||||||
|
|
||||||
:returns: IOU application identifier
|
|
||||||
"""
|
|
||||||
|
|
||||||
return self._used_application_ids.get(node_id, 1)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_legacy_vm_workdir(legacy_vm_id, name):
|
def get_legacy_vm_workdir(legacy_vm_id, name):
|
||||||
"""
|
"""
|
||||||
|
@ -65,7 +65,7 @@ class IOUVM(BaseNode):
|
|||||||
:param console: TCP console port
|
:param console: TCP console port
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, node_id, project, manager, path=None, console=None):
|
def __init__(self, name, node_id, project, manager, application_id=None, path=None, console=None):
|
||||||
|
|
||||||
super().__init__(name, node_id, project, manager, console=console)
|
super().__init__(name, node_id, project, manager, console=console)
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ class IOUVM(BaseNode):
|
|||||||
self._startup_config = ""
|
self._startup_config = ""
|
||||||
self._private_config = ""
|
self._private_config = ""
|
||||||
self._ram = 256 # Megabytes
|
self._ram = 256 # Megabytes
|
||||||
self._application_id = None
|
self._application_id = application_id
|
||||||
self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes).
|
self._l1_keepalives = False # used to overcome the always-up Ethernet interfaces (not supported by all IOSes).
|
||||||
|
|
||||||
def _config(self):
|
def _config(self):
|
||||||
@ -1141,9 +1141,7 @@ class IOUVM(BaseNode):
|
|||||||
|
|
||||||
:returns: integer between 1 and 512
|
:returns: integer between 1 and 512
|
||||||
"""
|
"""
|
||||||
if self._application_id is None:
|
|
||||||
#FIXME: is this necessary? application ID is allocated by controller and should not be None
|
|
||||||
return self._manager.get_application_id(self.id)
|
|
||||||
return self._application_id
|
return self._application_id
|
||||||
|
|
||||||
@application_id.setter
|
@application_id.setter
|
||||||
|
@ -24,13 +24,14 @@ log = logging.getLogger(__name__)
|
|||||||
def get_next_application_id(nodes):
|
def get_next_application_id(nodes):
|
||||||
"""
|
"""
|
||||||
Calculates free application_id from given nodes
|
Calculates free application_id from given nodes
|
||||||
|
|
||||||
:param nodes:
|
:param nodes:
|
||||||
:raises IOUError when exceeds number
|
:raises IOUError when exceeds number
|
||||||
:return: integer first free id
|
:return: integer first free id
|
||||||
"""
|
"""
|
||||||
used = set([n.properties.get('application_id') for n in nodes if n.node_type == 'iou'])
|
used = set([n.application_id for n in nodes])
|
||||||
pool = set(range(1, 512))
|
pool = set(range(1, 512))
|
||||||
try:
|
try:
|
||||||
return (pool - used).pop()
|
return (pool - used).pop()
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs reached)")
|
raise IOUError("Cannot create a new IOU VM (limit of 512 VMs on one host reached)")
|
||||||
|
@ -39,7 +39,6 @@ from ..utils.asyncio.pool import Pool
|
|||||||
from ..utils.asyncio import locked_coroutine
|
from ..utils.asyncio import locked_coroutine
|
||||||
from .export_project import export_project
|
from .export_project import export_project
|
||||||
from .import_project import import_project
|
from .import_project import import_project
|
||||||
from ..compute.iou.utils.application_id import get_next_application_id
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -86,7 +85,6 @@ class Project:
|
|||||||
self._show_grid = show_grid
|
self._show_grid = show_grid
|
||||||
self._show_interface_labels = show_interface_labels
|
self._show_interface_labels = show_interface_labels
|
||||||
self._loading = False
|
self._loading = False
|
||||||
self._add_node_lock = asyncio.Lock()
|
|
||||||
|
|
||||||
# Disallow overwrite of existing project
|
# Disallow overwrite of existing project
|
||||||
if project_id is None and path is not None:
|
if project_id is None and path is not None:
|
||||||
@ -439,13 +437,6 @@ class Project:
|
|||||||
if node_id in self._nodes:
|
if node_id in self._nodes:
|
||||||
return self._nodes[node_id]
|
return self._nodes[node_id]
|
||||||
|
|
||||||
with (yield from self._add_node_lock):
|
|
||||||
# wait for a node to be completely created before adding a new one
|
|
||||||
# this is important otherwise we allocate the same application ID
|
|
||||||
# when creating multiple IOU node at the same time
|
|
||||||
if node_type == "iou" and 'application_id' not in kwargs.keys():
|
|
||||||
kwargs['application_id'] = get_next_application_id(self._nodes.values())
|
|
||||||
|
|
||||||
node = Node(self, compute, name, node_id=node_id, node_type=node_type, **kwargs)
|
node = Node(self, compute, name, node_id=node_id, node_type=node_type, **kwargs)
|
||||||
if compute not in self._project_created_on_compute:
|
if compute not in self._project_created_on_compute:
|
||||||
# For a local server we send the project path
|
# For a local server we send the project path
|
||||||
|
@ -65,6 +65,8 @@ class IOUHandler:
|
|||||||
|
|
||||||
for name, value in request.json.items():
|
for name, value in request.json.items():
|
||||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||||
|
if name == "application_id":
|
||||||
|
continue # we must ignore this to avoid overwriting the application_id allocated by the IOU manager
|
||||||
if name == "startup_config_content" and (vm.startup_config_content and len(vm.startup_config_content) > 0):
|
if name == "startup_config_content" and (vm.startup_config_content and len(vm.startup_config_content) > 0):
|
||||||
continue
|
continue
|
||||||
if name == "private_config_content" and (vm.private_config_content and len(vm.private_config_content) > 0):
|
if name == "private_config_content" and (vm.private_config_content and len(vm.private_config_content) > 0):
|
||||||
@ -116,6 +118,8 @@ class IOUHandler:
|
|||||||
|
|
||||||
for name, value in request.json.items():
|
for name, value in request.json.items():
|
||||||
if hasattr(vm, name) and getattr(vm, name) != value:
|
if hasattr(vm, name) and getattr(vm, name) != value:
|
||||||
|
if name == "application_id":
|
||||||
|
continue # we must ignore this to avoid overwriting the application_id allocated by the IOU manager
|
||||||
setattr(vm, name, value)
|
setattr(vm, name, value)
|
||||||
|
|
||||||
if vm.use_default_iou_values:
|
if vm.use_default_iou_values:
|
||||||
|
Loading…
Reference in New Issue
Block a user